diff --git a/.gitignore b/.gitignore index 71a47aca6f0cb322c46981610abe785b73597f04..da71b5ba0d26201e9fe25fde79e37d09d1d3da55 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ CMakeFiles cmake_install.cmake stage +tests dng gipltng ost @@ -19,5 +20,8 @@ html scratch pov_*test.pov pov_*test.inc +*-out.pdb CMakeLists.txt.user OpenStructure.cbp +DartConfiguration.tcl +Testing diff --git a/CMakeLists.txt b/CMakeLists.txt index b0780e36e039f710e2d974196f76fb92b711f0cb..d59bd465412c9334bdc0c5be64a21d6be18678a2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,13 +6,15 @@ cmake_minimum_required(VERSION 2.6.4 FATAL_ERROR) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake_support) include(OST) - - project(OpenStructure CXX C) +INCLUDE(CTest) +ENABLE_TESTING() option(USE_SHADER "whether to compile with shader support" OFF) +option(SET_RPATH "embed rpath upon make install" + OFF) option(COMPILE_TMTOOLS "whether to compile the tmalign and tmscore programs" OFF) option(PROFILE "whether to compile with profiling support" @@ -28,7 +30,8 @@ option(USE_DOUBLE_PRECISION "whether to compile in double precision" option(ENABLE_SPNAV "whether 3DConnexion devices should be supported" OFF) option(STATIC_PROPERTY_WORKAROUND "workaround for static property bug with some boost/boost_python combinations" OFF) -option(DEPLOYMENT "switch on deployment settings" OFF) +option(DEPLOYMENT "switch on deployment settings" OFF) +option(COMPILE_TESTS "wheter unit tests should be compiled by default" OFF) if (PREFIX) set(CMAKE_INSTALL_PREFIX ${PREFIX}) @@ -218,13 +221,25 @@ include_directories(${Boost_INCLUDE_DIRS} ${TIFF_INCLUDE_DIR} ${SPNAV_INCLUDE_DIR} ) - +if (UNIX) + SET(CMAKE_SKIP_BUILD_RPATH FALSE) + SET(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) + if(USE_RPATH) + set(_USE_RPATH ON) + SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${LIB_DIR}") + SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) + else() + set(_USE_RPATH OFF) + SET(CMAKE_INSTALL_RPATH "") + SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE) + endif() +endif() add_subdirectory(modules) add_subdirectory(scripts) -add_subdirectory(deployment) -set (FILES_TO_BE_REMOVED stage CMakeFiles) +add_subdirectory(deployment) +set(FILES_TO_BE_REMOVED CMakeFiles stage tests) set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${FILES_TO_BE_REMOVED}") @@ -232,6 +247,7 @@ set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES message(STATUS "OpenStructure will be built with the following options:\n" + " RPath in install (-DUSE_RPATH) : ${_USE_RPATH}\n" " Graphical interface (-DENABLE_UI) : ${_UI}\n" " OpenGL support (-DENABLE_GFX) : ${_OPENGL}\n" " Image Processing support (-DENABLE_IMG) : ${_IMG}\n" @@ -245,4 +261,4 @@ message(STATUS #set(SPHINX_OPTIONS -c doc/conf -b html -d doc/html/doctrees) #add_custom_target(doc COMMAND # ${SPHINX} ${SPHINX_OPTIONS} modules doc/html -# VERBATIM) \ No newline at end of file +# VERBATIM) diff --git a/CTestConfig.cmake b/CTestConfig.cmake new file mode 100644 index 0000000000000000000000000000000000000000..1de92e23ab98b0b4ff7860ba2270a7716608bf99 --- /dev/null +++ b/CTestConfig.cmake @@ -0,0 +1,31 @@ +## This file should be placed in the root directory of your project. +## Then modify the CMakeLists.txt file in the root directory of your +## project to incorporate the testing dashboard. +## # The following are required to uses Dart and the Cdash dashboard +## ENABLE_TESTING() +## INCLUDE(CTest) +set(CTEST_PROJECT_NAME "OpenStructure") +set(CTEST_NIGHTLY_START_TIME "00:00:00 MEZ") + +set(CTEST_DROP_METHOD "http") +set(CTEST_DROP_SITE "kb-pdwg1059-06.pz.unibas.ch") +set(CTEST_DROP_LOCATION "/cdash/submit.php?project=OpenStructure") +set(CTEST_DROP_SITE_CDASH TRUE) + +if ("${CMAKE_NATIVE_ARCH}" MATCHES "64") + set(CMAKE_SYSTEM_NAME "${CMAKE_SYSTEM_NAME}64bit") +endif() +if (USE_DOUBLE_PRECISION) + set(CMAKE_SYSTEM_NAME "${CMAKE_SYSTEM_NAME}-double") +endif() +if (NOT ENABLE_IMG) + set(CMAKE_SYSTEM_NAME "${CMAKE_SYSTEM_NAME}-no_img") +endif() +if (NOT ENABLE_GFX) + set(CMAKE_SYSTEM_NAME "${CMAKE_SYSTEM_NAME}-no_gfx") +endif() +if (NOT ENABLE_UI) + set(CMAKE_SYSTEM_NAME "${CMAKE_SYSTEM_NAME}-no_ui") +endif() + +set(BUILDNAME "${CMAKE_SYSTEM_NAME}") diff --git a/cmake_support/OST.cmake b/cmake_support/OST.cmake index 6d04eb292ea2121296bf810f1e3a92514e46f9b7..e46d6f53ca1474b85366ba2def8ef28a518c55c5 100644 --- a/cmake_support/OST.cmake +++ b/cmake_support/OST.cmake @@ -190,12 +190,11 @@ macro(module) set_target_properties(${_LIB_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${LIB_STAGE_PATH} ARCHIVE_OUTPUT_DIRECTORY ${LIB_STAGE_PATH} - RUNTIME_OUTPUT_DIRECTORY ${LIB_STAGE_PATH} - INSTALL_RPATH "." - INSTALL_NAME_DIR "@rpath") + RUNTIME_OUTPUT_DIRECTORY ${LIB_STAGE_PATH}) if (APPLE) set_target_properties(${_LIB_NAME} PROPERTIES - LINK_FLAGS "-Wl,-rpath,.") + LINK_FLAGS "-Wl,-rpath,." + INSTALL_NAME_DIR "@rpath") endif() if (WIN32) #set_target_properties(${_LIB_NAME} PROPERTIES PREFIX "../") @@ -390,13 +389,20 @@ macro(pymod) endif() target_link_libraries("_${_ARG_NAME}" ${_PARENT_LIB_NAME} ${PYTHON_LIBRARIES} ${BOOST_PYTHON_LIBRARIES}) - set_target_properties("_${_ARG_NAME}" - PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PYMOD_STAGE_DIR} - INSTALL_NAME_DIR "@rpath") + if (_USE_RPATH) + set_target_properties("_${_ARG_NAME}" + PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PYMOD_STAGE_DIR} + INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${LIB_DIR}") + else() + set_target_properties("_${_ARG_NAME}" + PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PYMOD_STAGE_DIR} + INSTALL_RPATH "") + endif() if (APPLE) file(RELATIVE_PATH _REL_PATH "${PYMOD_STAGE_DIR}" "${LIB_STAGE_PATH}") set_target_properties(_${_ARG_NAME} PROPERTIES - LINK_FLAGS "-Wl,-rpath,@${_REL_PATH}") + LINK_FLAGS "-Wl,-rpath,@${_REL_PATH}" + INSTALL_NAME_DIR "@rpath") endif() if (NOT WIN32) set_target_properties("_${_ARG_NAME}" @@ -474,6 +480,7 @@ macro(ost_unittest MODULE SOURCE_FILES) set(_SOURCES ${SOURCE_FILES}) set(CPP_TESTS) set(PY_TESTS) + set(CMAKE_CURRENT_BINARY_DIR "${CMAKE_BINARY_DIR}/tests") foreach(src ${_SOURCES}) if (${src} MATCHES "\\.py$") list(APPEND PY_TESTS "${src}") @@ -484,22 +491,28 @@ macro(ost_unittest MODULE SOURCE_FILES) set(_SOURCES ${CPP_TESTS}) set(_test_name "${MODULE}_tests") if(DEFINED CPP_TESTS) - add_executable(${_test_name} EXCLUDE_FROM_ALL ${_SOURCES}) + if(COMPILE_TESTS) + add_executable(${_test_name} ${_SOURCES}) + else() + add_executable(${_test_name} EXCLUDE_FROM_ALL ${_SOURCES}) + endif() if (WIN32) - target_link_libraries(${_test_name} "ost_${MODULE}") + target_link_libraries(${_test_name} ${BOOST_UNIT_TEST_LIBRARIES} "ost_${MODULE}") add_custom_target("${_test_name}_run" COMMAND ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/${_test_name}.exe || echo - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${CMAKE_BUILD_TYPE}/.. COMMENT "running checks for module ${MODULE}" DEPENDS ${_test_name}) + add_test("${_test_name}" ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/${_test_name}.exe) else() target_link_libraries(${_test_name} ${BOOST_UNIT_TEST_LIBRARIES} "ost_${MODULE}") add_custom_target("${_test_name}_run" - COMMAND ${CMAKE_CURRENT_BINARY_DIR}/${_test_name} || echo - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/${_test_name} || echo + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMENT "running checks for module ${MODULE}" DEPENDS ${_test_name}) + add_test("${_test_name}" ${CMAKE_CURRENT_BINARY_DIR}/${_test_name} ) endif() add_dependencies(check "${_test_name}_run") @@ -513,13 +526,17 @@ macro(ost_unittest MODULE SOURCE_FILES) foreach(py_test ${PY_TESTS}) if(WIN32) set (PY_TESTS_CMD "${EXECUTABLE_OUTPUT_PATH}/ost.bat") + add_custom_target("${py_test}_run" + CALL "${PY_TESTS_CMD} ${CMAKE_CURRENT_SOURCE_DIR}/${py_test} || echo" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMENT "running checks ${py_test}" VERBATIM) else() set (PY_TESTS_CMD "${EXECUTABLE_OUTPUT_PATH}/ost") + add_custom_target("${py_test}_run" + sh -c "${PY_TESTS_CMD} ${CMAKE_CURRENT_SOURCE_DIR}/${py_test} || echo" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMENT "running checks ${py_test}" VERBATIM) endif() - add_custom_target("${py_test}_run" - COMMAND ${PY_TESTS_CMD} ${CMAKE_CURRENT_SOURCE_DIR}/${py_test} || echo - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - COMMENT "running checks ${py_test}" VERBATIM) add_dependencies("${py_test}_run" ost_scripts "_${MODULE}") add_dependencies(check "${py_test}_run") if (WIN32) @@ -626,4 +643,4 @@ macro(get_ost_rev) endif() endif() message("Revision: ${OST_REV}") -endmacro() \ No newline at end of file +endmacro() diff --git a/doc/conf/conf.py b/doc/conf/conf.py index d7a1455a17fa44609c07625ed99d33de930ce6f1..9e720456c9f9cc6a11c8a6741be2e7ce5ae06d9c 100644 --- a/doc/conf/conf.py +++ b/doc/conf/conf.py @@ -16,8 +16,10 @@ import sys, os # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.append(os.path.abspath('.')) - +sys.path.append(os.path.join(os.path.abspath('../..'), + 'stage/lib/openstructure')) +sys.path.append(os.path.join(os.path.abspath('../..'), + 'stage/lib64/openstructure')) # -- General configuration ----------------------------------------------------- # Add any Sphinx extension module names here, as strings. They can be extensions @@ -86,7 +88,7 @@ exclude_trees = [] pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] +modindex_common_prefix = ['ost.'] # -- Options for HTML output --------------------------------------------------- diff --git a/doc/make.py b/doc/make.py new file mode 100644 index 0000000000000000000000000000000000000000..d5b75c2ab130f1d9ab0dcfd6081c918b7869a899 --- /dev/null +++ b/doc/make.py @@ -0,0 +1,48 @@ +import os, sys +import shutil +if len(sys.argv)==2: + root_dir=sys.argv[1] +else: + root_dir='.' + +def _OutputPath(inpath, outdir): + parts=inpath.split(os.path.sep) + filtered_parts=[outdir] + index=parts.index('modules') + for part in parts[index+1:]: + if part!='doc': + filtered_parts.append(part) + return os.path.join(*filtered_parts) + +def _RequireCopy(in_name, out_name): + if not os.path.exists(out_name): + return True + if os.path.getmtime(in_name)>os.path.getmtime(out_name): + return True + return False +def _MkDir(dirname): + """ + Recursively create directories if they don't exist + """ + parts=dirname.split(os.path.sep) + for i, d in enumerate(parts): + n=os.path.join(*parts[:1+i]) + if not os.path.exists(n): + os.mkdir(n) + +def _CollectRstDocs(outdir, dirname, fnames): + for fname in fnames: + if fname.endswith('.rst'): + in_name=os.path.join(dirname, fname) + out_name=_OutputPath(in_name, outdir) + out_dir=os.path.dirname(out_name) + if not os.path.exists(out_dir): + _MkDir(out_dir) + if _RequireCopy(in_name, out_name): + print 'cp %s %s' % (in_name, out_name) + os.system('cp %s %s' % (in_name, out_name)) + +for sub_dir in ('modules',): + os.path.walk(sub_dir, _CollectRstDocs, 'doc/source') +os.system('sphinx-build -b html -c %s %s %s' % ('doc/conf', 'doc/source', + 'doc/build')) \ No newline at end of file diff --git a/examples/dokk/datafiles/dengue/levelF.ini b/examples/dokk/datafiles/dengue/levelF.ini index 55afca839941045110cf3131fd15dbf1a2790fbb..c1e13d14aa8e06c1dca50b266fe5a12c4d5e0c43 100644 --- a/examples/dokk/datafiles/dengue/levelF.ini +++ b/examples/dokk/datafiles/dengue/levelF.ini @@ -16,14 +16,15 @@ TEXT_COUNT: 10 TEXT1: Voil�, la phase d'entrainement du jeu est termin�e ... TEXTTIME1: 3000 -TEXT2: Au niveau suivant, vous devez approcher/docker le ligand sur la prot�ine aussi bien que possible. +TEXT2: Au niveau suivant, vous devez approcher/docker le ligand sur la prot�ine + aussi bien que possible. TEXTTIME2: 8000 TEXT3: La premi�re cible est une enzyme importante du virus de la dengue. TEXTTIME3: 8000 -TEXT4: Pour arr�ter le virus de la dengue, placez le ligand, le mieux que vous le pouvez, - � l'int�rieur de la prot�ine. +TEXT4: Pour arr�ter le virus de la dengue, placez le ligand, le mieux que vous le + pouvez, � l'int�rieur de la prot�ine. TEXTTIME4: 8000 TEXT5: Vous pouvez lire votre score actuel en haut � gauche de l'�cran. Si vous �tes diff --git a/examples/dokk/datafiles/dengue/top_ten.ini b/examples/dokk/datafiles/dengue/top_ten.ini index 30fb5b557379f9f0d54527a7fca0d7ddffd7d413..186a0ffdc681ca051cefddd616ea6c1b5442b507 100644 --- a/examples/dokk/datafiles/dengue/top_ten.ini +++ b/examples/dokk/datafiles/dengue/top_ten.ini @@ -1,6 +1,6 @@ [10] -score = 2.80041636229 -name = AAA +score = 2.58003196716 +name = STU [1] score = 1.06508742174 @@ -23,18 +23,18 @@ score = 1.22069145838 name = STU [7] -score = 1.57162377437 +score = 1.34045518637 name = STU [6] -score = 1.34045518637 -name = STU +score = 1.32533345222 +name = PAA [9] -score = 2.58003196716 -name = STU - -[8] score = 2.31934833527 name = ASS +[8] +score = 1.57162377437 +name = STU + diff --git a/examples/seq/seq_viewer.py b/examples/seq/seq_viewer.py new file mode 100644 index 0000000000000000000000000000000000000000..2d52392538ffe8bb8df25093f087535f928ece7b --- /dev/null +++ b/examples/seq/seq_viewer.py @@ -0,0 +1,4 @@ +aln=io.LoadAlignment('sh2.aln') +v=gui.SequenceViewerV2() +v.AddAlignment(aln) +v.Show() diff --git a/examples/seq/sh2.aln b/examples/seq/sh2.aln new file mode 100644 index 0000000000000000000000000000000000000000..45daa963b90571581ffe75d3904757efafe107a8 --- /dev/null +++ b/examples/seq/sh2.aln @@ -0,0 +1,214 @@ +CLUSTAL 2.0.12 multiple sequence alignment + + +SH2 -------------------------KP-HPWFFGKIPRAKAEEMLSKQR- 23 +UniRef90_UPI0000EB201F KAELNGKDGFIPKN-------YIEMKP-HPWFFGKIPRAKAEEMLSKQR- 45 +UniRef90_P62993 KAELNGKDGFIPKN-------YIEMKP-HPWFFGKIPRAKAEEMLSKQR- 78 +UniRef90_P62993-2 KAELNGKDGFIPKN-------YIEMKP-HP-------------------- 59 +UniRef90_P87379 KAELNGKDGFIPKN-------YIEMKA-HPWFFGKIPRAKAEEMLGKQR- 78 +UniRef90_UPI00016E653C KAELRGKDGFIPKN-------YIEMKA-HPWFYGKIPRAKAEEILNKQR- 78 +UniRef90_UPI00016E653B KAELRGKDGFIPKN-------YIEMKA-HPWFYGKIPRAKAEEILNKQR- 78 +UniRef90_Q4T656 DQALS-FASLLPVS-------FSAC---CRWFYGKIPRAKAEEILNKQR- 75 +UniRef90_UPI0001555716 KAELNGKDGFIPKN-------YIEMKP-HLWFFGKIPRAYAEEMLGKQL- 388 +UniRef90_UPI000180AF26 KAEQDGKEGLVPMN-------YIQMKP-CEWFARNMTRANAELRL-KNA- 52 +UniRef90_UPI000180AF37 KAEQDGKEGLVPMN-------YIEIKE-CEWFARNMTRANAELRL-KNT- 77 +UniRef90_A8XPY6 KAELDGTEGFIPSN-------YIRMGD-CSWYLGKITRNDAEVLLKKSNV 79 +UniRef90_P29355 KAELDGNEGFIPSN-------YIRMTE-CNWYLGKITRNDAEVLLKKPTV 79 +UniRef90_UPI000186E6C5 RAELDSKEGLIPSN-------YIEMKN-HDWYYGRITRADAEKLLMNK-- 77 +UniRef90_Q08012 RAELDGKEGLIPSN-------YIEMKN-HDWYYGRITRADAEKLLSNK-- 77 +UniRef90_B7P0R2 RAELDSKEGLIPSN-------YIEMKK-HDWYYGRITRADAEKLLSNK-- 77 +UniRef90_D3PIQ8 RAESGGKEGLIPSN-------YIDMKP-HDWYYSRMTRATAEKLLSNK-- 77 +UniRef90_C4WWT7 RAEFEGKEGLIPSN-------YIEMKN-HDWYYGKITRADAEKLLDQQ-- 77 +UniRef90_UPI0000586DB6 -------------------------------------RDGAEELLKND-- 40 +UniRef90_UPI0001CBA623 KAELDGREGFIPKN-------YITMRP-HDWFHGKISRAKAEELLQLQP- 78 +UniRef90_UPI0001CBA624 NAELDGREGLIPKN-------YIEMKP-HEWFHGKISREKAEELLQLQS- 77 +UniRef90_UPI000192619C KAEQNGKEGFVPKN-------YIQMKP-HSWYYGKIRRSEAEQLLLQEP- 52 +UniRef90_UPI0000521DDC RAEIDGRMGLVPKN-------YIELKA-HDWYHGKISRVKAEQSLNKPHY 79 +UniRef90_C1LZF7 LAEQEGRTGLIPCN-------YITMRP-HPWYIRHCSRMEAEERLQEIDQ 79 +UniRef90_UPI0000E478D2 LAHQGAKQGLVPEN-------YLKIEKSHPWYVGKISRKVAEEYLMSMP- 80 +UniRef90_UPI0000E49A1C ----------MGPK-------HTYPEIAMAWFFPTITRKNAELLLMQE-- 31 +UniRef90_A8E5T1 KAELFGREGYIPKN-------YIKVKP-HPWYAGRISRQVAEEILLKRNF 79 +UniRef90_C1C3T6 KAELKGQEGYIPKN-------YIKVKP-HPWYAGRISRQVAEEILLKKRF 79 +UniRef90_Q13588 KAELRGVEGFIPKN-------YIRVKP-HPWYSGRISRQLAEEILMKRNH 79 +UniRef90_UPI0001C606E3 KAELRGAEGFVPKN-------YIHIKP-HPWYSGRISRQLAEEILMKRNQ 79 +UniRef90_Q9CX99 KAELRGAEGFVPKN-------YIRVKP-HPWYSGRISRQLAEETLMKRNH 79 +UniRef90_UPI0000DA3575 GVGLKPIEGMRPTNRTXRIPADIVPSP-HRWYSGRISRQLAEETLMKRNH 86 +UniRef90_UPI0000D9440A KAELRGAEGFIPKN-------YIQVKP-HPWFAGRISRQFAEEILLRRNH 79 +UniRef90_UPI000155C0E1 RTSLLGGESFFYKN-------IQKLSP-SPWYAGRISRQLAEEVLLKRNH 79 +UniRef90_UPI0000E80FCB KAELYGCEGFVPKN-------YIKVKP-HPWYAGRISRHVAEELLLKRRY 79 +UniRef90_UPI00016E4BE7 TAELHNRKGFVPKN-------YINLRP-HAWFAGRISRSVAESRLRQRE- 78 +UniRef90_Q503S8 TAEFVNRKGYVPKN-------YISLRP-HAWFAGRISRHVAENRLHQRD- 78 +UniRef90_Q4V9Q1 TAELLGRRGYVPKN-------YINVRP-HTWFVGGISRQAAENRLRPLE- 78 +UniRef90_UPI00017B202F TAEIQGKRGYIPQN-------YISLLP-YPWFVGRVSRLEAEKRLRWQD- 78 +UniRef90_UPI0000E25B42 KAELGSQEGYVPKN-------FIDIQF-PEWFHEGLSRHQAENLLMGKE- 149 +UniRef90_O75791 KAELGSQEGYVPKN-------FIDIQF-PKWFHEGLSRHQAENLLMGKE- 76 +UniRef90_B7Z8F8 RHKLNP---FSSK----------------RWFHEGLSRHQAENLLMGKE- 50 +UniRef90_UPI00005BC6B6 KAELGSQEGYVPKN-------FIEIEF-PEWFHEGLSRHQAESLLMGKE- 76 +UniRef90_O89100 KAELGSQEGYVPKN-------FIDIEF-PEWFHEGLSRHQAENLLMGKD- 76 +UniRef90_UPI0000EDE7DF KAELKSHEGYVPKN-------FIDIHI-PGWFHEGISRHEAESLLMGKE- 76 +UniRef90_UPI0000F2E19C KAELGSQEGYVPKN-------FIDIQF-PSWFHEDISRHDAESLLMGKD- 241 +UniRef90_UPI0000E7F8B9 KAELRSQEGYVPKN-------FIDFHV-PPWFDEKISRHEAESILMNKG- 76 +UniRef90_UPI0000ECD2B7 KAELRSQEGYVPKN-------FIDFHV-PPWFDEKISRHEAESILMNKG- 76 +UniRef90_UPI000194E163 KAELRSHEGYVPKN-------FIDFHV-PHWFDEKISRHEAENLLMSKG- 91 +UniRef90_B5X487 KAELHGQEGFVPQN-------YIERQT-PSWFKETASRSSAEELLMSRE- 76 +UniRef90_Q567F1 KAELHGHEGYVPKN-------YVDRQI-PSWFKESASRGSAEETLMSRE- 76 + + +SH2 -------HDGAFLIRESESA--PGDFSL----SVKFGNDVQHFKVLR--D 58 +UniRef90_UPI0000EB201F -------HDGAFLIRESESA--PGDFSL----SVKFGNDVQHFKVLR--D 80 +UniRef90_P62993 -------HDGAFLIRESESA--PGDFSL----SVKFGNDVQHFKVLR--D 113 +UniRef90_P62993-2 -----------------------------------FGNDVQHFKVLR--D 72 +UniRef90_P87379 -------HDGAFLIRESESA--PGDFSL----SVKFGNDVQHFKVLR--D 113 +UniRef90_UPI00016E653C -------RDGAFLIRESESA--PGDFSL----SVKYGNDVQHFKVLR--D 113 +UniRef90_UPI00016E653B -------RDGAFLIRESESA--PGDFSL----SVKYGNDVQHFKVLR--D 113 +UniRef90_Q4T656 -------RDGAFLIRESESA--PGDFSL----SVKYGNDVQHFKVLR--D 110 +UniRef90_UPI0001555716 -------NYGSFFILXXXXP--PGDALTGARSTPRFGNDVQHFKVLR--D 427 +UniRef90_UPI000180AF26 -------LDESFLVRESEST--PGDFSL----SVKTNSGVQHFKVLR--D 87 +UniRef90_UPI000180AF37 -------LDGSFLVRESEST--PGEFSV----SVKTNSGVQHFKVLR--D 112 +UniRef90_A8XPY6 -------RDGHFLVRQCESS--PGEFSI----SVRFQDSVQHFKVLR--D 114 +UniRef90_P29355 -------RDGHFLVRQCESS--PGEFSI----SVRFQDSVQHFKVLR--D 114 +UniRef90_UPI000186E6C5 -------HEGAFLIRVSESS--PGDFSL----SVKCSDGVQHFKVLR--D 112 +UniRef90_Q08012 -------HEGAFLIRISESS--PGDFSL----SVKCPDGVQHFKVLR--D 112 +UniRef90_B7P0R2 -------HEGAFLIRVSESS--PGDFSL----SVRCGDGVQHFKVLR--D 112 +UniRef90_D3PIQ8 -------HEGAFVIRVSESS--PGDFSL----SVKCGDGVQHFKVLR--D 112 +UniRef90_C4WWT7 -------PEGCFLVRISESS--PGDFSL----SVKCGDGVQHFKVLR--D 112 +UniRef90_UPI0000586DB6 -------GDGAFLIRESEGT--PGDYSL----SVKFVDGVQHFKVLR--D 75 +UniRef90_UPI0001CBA623 -------HDGAFLIRESESA--PGDFSL----SVKFKDEVQHFKVLR--D 113 +UniRef90_UPI0001CBA624 -------YDGAFLIRESEST--PGDFSL----SVKFKDGVQNFKILR--D 112 +UniRef90_UPI000192619C -------HDGAYLIRDSEST--AGDFSL----SVKFNNQVQHFKVLR--D 87 +UniRef90_UPI0000521DDC -------PDGAFLIRESESS--PGDFSL----SVKYGSAVQHFKVLR--D 114 +UniRef90_C1LZF7 ETAQHLQPDGAFILRQSEAD--GKGFSL----SVKQGCEVLHFKVLQ--D 121 +UniRef90_UPI0000E478D2 -------SDGAFMIRDSESNPDSGNFSL----SVKFRDQVQHFKILT--D 117 +UniRef90_UPI0000E49A1C -------RNGAFLVRRSESS--EGLYSL----SVKYNESVQHFRILQ--D 66 +UniRef90_A8E5T1 --------VGAFLIRDSESS--PGDFSI----SVNYGHHVQHFKVLRDTE 115 +UniRef90_C1C3T6 --------LGAFLIRDSESS--PGEFSI----SVNYGHHVQHFKVLR--E 113 +UniRef90_Q13588 --------LGAFLIRESESS--PGEFSV----SVNYGDQVQHFKVLR--E 113 +UniRef90_UPI0001C606E3 --------LGAFLIRESESS--PGEFSV----SVNYGDQVQHFKVLR--E 113 +UniRef90_Q9CX99 --------LGAFLIRESESS--PGEFSV----SVNYGDQVQHFKVLR--E 113 +UniRef90_UPI0000DA3575 --------LGAFLIRESESS--PGEFSV----SVNYGDQVQHFKVLR--E 120 +UniRef90_UPI0000D9440A --------LGAFLIRESESS--PGEFSV----SVNYGNQVQHFKVLR--E 113 +UniRef90_UPI000155C0E1 --------LGAFLIRESESS--PGEFSV----SVNYGDQVQHFKVLR--E 113 +UniRef90_UPI0000E80FCB --------VGAFLIRESESA--PGEFSI----SVNYGQHVQHFKVLR--E 113 +UniRef90_UPI00016E4BE7 --------CGAFLVRESESA--PGEFSM----SVSYGDHVQHFKVLQD-- 112 +UniRef90_Q503S8 --------CGSFLVRESESA--PGEFSM----SVSYGDHVQHFKVLKD-- 112 +UniRef90_Q4V9Q1 --------CGAFLIRESEST--PGEFSV----SVSYGDHVQHFKVLKD-- 112 +UniRef90_UPI00017B202F --------PGVFLVRESESA--PGEFSV----SVSYGNRVEHFRVLE--- 111 +UniRef90_UPI0000E25B42 --------VGFFIIRASQSS--PGDFSI----SVRHEDDVQHFKVMR--D 183 +UniRef90_O75791 --------VGFFIIRASQSS--PGDFSI----SVRHEDDVQHFKVMR--D 110 +UniRef90_B7Z8F8 --------VGFFIIRASQSS--PGDFSI----SVRHEDDVQHFKVMR--D 84 +UniRef90_UPI00005BC6B6 --------LGCFIIRASQSS--PGDFSI----SVRHEDDVQHFKVMR--D 110 +UniRef90_O89100 --------IGFFIIRASQSS--PGDFSI----SVRHEDDVQHFKVMR--D 110 +UniRef90_UPI0000EDE7DF --------VGSFIIRASQSS--PGDFSI----SVRHEDDVQHFKVMR--D 110 +UniRef90_UPI0000F2E19C --------VGSFIIRASQSS--PGDFSI----SVRHEDDVQHFKVMR--D 275 +UniRef90_UPI0000E7F8B9 --------VGSFIVRASQNS--HGDFSI----SVRHEDDVQHFKVMR--D 110 +UniRef90_UPI0000ECD2B7 --------VGSFIVRASQNS--HGDFSI----SVRHEDDVQHFKVMR--D 110 +UniRef90_UPI000194E163 --------VGCFVVRASQNS--HGDFSI----SVRHEDDVQHFKVMR--D 125 +UniRef90_B5X487 --------VGGFLIRGSQSS--PGEFSI----SVRHEFDVQHFKVMK--D 110 +UniRef90_Q567F1 --------VGAFLIRGSQSS--PGDFSI----SVRHDYDVQHFKVMK--D 110 + * :*::: + +SH2 GAGKYFLWVVKFNSLNELVDYHRSTSVSR---------------NQQIFL 93 +UniRef90_UPI0000EB201F GAGKYFLWVVKFNSLNELVDYHRSTSVSR---------------NQQIFL 115 +UniRef90_P62993 GAGKYFLWVVKFNSLNELVDYHRSTSVSR---------------NQQIFL 148 +UniRef90_P62993-2 GAGKYFLWVVKFNSLNELVDYHRSTSVSR---------------NQQIFL 107 +UniRef90_P87379 GAGKYFLWVVKFNSLNELVDYHRSTSVSR---------------NQQIFL 148 +UniRef90_UPI00016E653C GAGKYFLWVVKFNSLNELVEYHRTTSVSR---------------NQQIFL 148 +UniRef90_UPI00016E653B GAGKYFLWVVKFNSLNELVEYHRTTSVSR---------------NQQIFL 148 +UniRef90_Q4T656 GAGKYFLWVVKFTSLNELVEYHRTTSVSR---------------NQQIFL 145 +UniRef90_UPI0001555716 GAGKYFLWVVKFNSLNELVDYHRSTSVSR---------------NQQIFL 462 +UniRef90_UPI000180AF26 GAGKYFIWLVKFKSLNQLVDYHRTSSVSR---------------SEQILL 122 +UniRef90_UPI000180AF37 GAGKYFIWVVKFSSLNELVVYHRVMTVSG---------------SERIFL 147 +UniRef90_A8XPY6 QNGKYYLWAVKFNSLNELVAYHRTASVSR---------------THTILL 149 +UniRef90_P29355 QNGKYYLWAVKFNSLNELVAYHRTASVSR---------------THTILL 149 +UniRef90_UPI000186E6C5 AQGKFFLWVVKFSSLNELVEYHRTSSVSR---------------SQHVKL 147 +UniRef90_Q08012 AQSKFFLWVVKFNSLNELVEYHRTASVSR---------------SQDVKL 147 +UniRef90_B7P0R2 TLGKFFLWVVKFASLNELVEYHRSASVSR---------------SQDIKL 147 +UniRef90_D3PIQ8 GQGKFFLWVVKFNSLNELVEYHHSASVSR---------------SQDIKL 147 +UniRef90_C4WWT7 AQAKFFLWVVKFDSLNELVDYHRESSVSR---------------SQDVRL 147 +UniRef90_UPI0000586DB6 GAGKYFLWVVKFNSLNQLVEYHRTSSVSR---------------SQTIYL 110 +UniRef90_UPI0001CBA623 GAGKYFLWVVKFNSLNELVEYHRSSSVSR---------------TQTIYL 148 +UniRef90_UPI0001CBA624 GAGKYFLWVVKFNSLNQLVDYHRTSSVSR---------------SEQIFL 147 +UniRef90_UPI000192619C GAGKYFLWVVKFNSLNQLVEYHRAASVSR---------------SQTIYL 122 +UniRef90_UPI0000521DDC GAGKYFLWVVKFSSLNELIKYHREQSISR---------------TQQIML 149 +UniRef90_C1LZF7 EAGKYFFWLSKFDSINQLIDHHRKTSISR---------------NRLLTL 156 +UniRef90_UPI0000E478D2 LAGKYFLWVVKFTSINDLVDYHKDNSVSRTQEIVLNEPCVPIEDANQRPQ 167 +UniRef90_UPI0000E49A1C TAGKFHLWIVKFPSLDALVDYYRTTSVTR---------------ENQVST 101 +UniRef90_A8E5T1 SNGKYYLWEAKFNSLNELVDYYRRHSIAK---------------FHEVFL 150 +UniRef90_C1C3T6 KSGTYFLWETKFGSLNELVEFYRSSSIAK---------------THPVLL 148 +UniRef90_Q13588 ASGKYFLWEEKFNSLNELVDFYRTTTIAK---------------KRQIFL 148 +UniRef90_UPI0001C606E3 ASGKYFLWEEKFNSLNELVDFYRTTTIAK---------------KRQIFL 148 +UniRef90_Q9CX99 ASGKYFLWEEKFNSLNELVDFYRTTTIAK---------------RRQIFL 148 +UniRef90_UPI0000DA3575 ASGKYFLWEEKFNSLNELVDFYRTTTIAK---------------RRQIFL 155 +UniRef90_UPI0000D9440A NMGKYFLWEEKFNSLNELVDFYRTTTIAK---------------KKQIFL 148 +UniRef90_UPI000155C0E1 RIGKYYLWEEKFNSLNELVDFYRTTTIAK---------------KKQIFL 148 +UniRef90_UPI0000E80FCB RNGKYFLWEEKFNSLNELVDFYRTTTIAK---------------KQQIFL 148 +UniRef90_UPI00016E4BE7 RGGQYYVWDELFPSLNELVEFYHCNSIAR---------------ERTVLL 147 +UniRef90_Q503S8 REGYYFVWEEIFPSLNQLVDFYKTNSIAK---------------ERTVFL 147 +UniRef90_Q4V9Q1 GLGQYFIWDEVFSSLNQLVDFYRINSIAK---------------ERTVFL 147 +UniRef90_UPI00017B202F GGGQYCIWEESFCSLNRLVDFYRTHSIAM---------------DKVVCL 146 +UniRef90_UPI0000E25B42 NKGNYFLWTEKFPSLNKLVDYYRTNSISR---------------QKQIFL 218 +UniRef90_O75791 NKGNYFLWTEKFPSLNKLVDYYRTNSISR---------------QKQIFL 145 +UniRef90_B7Z8F8 NKGNYFLWTEKFPSLNKLVDYYRTNSISR---------------QKQIFL 119 +UniRef90_UPI00005BC6B6 NKGNYFLWTEKFPSLNKLVDYYRKNSISK---------------QKQIFL 145 +UniRef90_O89100 TKGNYFLWTEKFPSLNKLVDYYRTTSISK---------------QKQVFL 145 +UniRef90_UPI0000EDE7DF AKGHYFLWTEKFQSLNRLVEFYKTSSISR---------------QKQIFL 145 +UniRef90_UPI0000F2E19C AKGHYFLWTEKFQSLNQLVNFYRTSSISK---------------QKQIYL 310 +UniRef90_UPI0000E7F8B9 SKGNYYLWTEKFYSLNKLVDYYRTSTISR---------------QKQILL 145 +UniRef90_UPI0000ECD2B7 SKGNYYLWTEKFYSLNKLVDYYRTSTISR---------------QKQILL 145 +UniRef90_UPI000194E163 SKGSYYLWTEKFHSLNKLVDYYKTSSISR---------------QKQIFL 160 +UniRef90_B5X487 SKGHYFLWSEKFTSLNKLVDFYKNTSISK---------------QRDIYL 145 +UniRef90_Q567F1 KSGHYYLWTEKFTSLNKLVDFYKTTSISK---------------QKEIFL 145 + . : .* * *:: *: .:: ::: . + +SH2 RDIEQVP------------------------------------------- 100 +UniRef90_UPI0000EB201F RDIEQVPQQNSIFSLCQR----TSLTLCSIVSLEASEEENPVVREWSPHS 161 +UniRef90_P62993 RDIEQVP------------------------------------------- 155 +UniRef90_P62993-2 RDIEQVP------------------------------------------- 114 +UniRef90_P87379 RDIEQVPQVHGGDRATS--------------------------------- 165 +UniRef90_UPI00016E653C REIEQ--------------------------------------------- 153 +UniRef90_UPI00016E653B REIEQVTQVNVGTHYIN--------------------------------- 165 +UniRef90_Q4T656 RDIEQVTQV----------------------------------------- 154 +UniRef90_UPI0001555716 RDIEQMPQQKSPVCDRLS----FLFCAVNCRACSDGVFHG---------- 498 +UniRef90_UPI000180AF26 RHPIIS-------------------------------------------- 128 +UniRef90_UPI000180AF37 LHPIS--------------------------------------------- 152 +UniRef90_A8XPY6 ADMNV--------------------------------------------- 154 +UniRef90_P29355 SDMNV--------------------------------------------- 154 +UniRef90_UPI000186E6C5 RDMVP--------------------------------------------- 152 +UniRef90_Q08012 RDMIP--------------------------------------------- 152 +UniRef90_B7P0R2 RDMHP--------------------------------------------- 152 +UniRef90_D3PIQ8 KEIIC--------------------------------------------- 152 +UniRef90_C4WWT7 RDMPAATQNG---------------------------------------- 157 +UniRef90_UPI0000586DB6 KDRKS--------------------------------------------- 115 +UniRef90_UPI0001CBA623 LKMHV--------------------------------------------- 153 +UniRef90_UPI0001CBA624 KDKQ---------------------------------------------- 151 +UniRef90_UPI000192619C KDMTN--------------------------------------------- 127 +UniRef90_UPI0000521DDC VDLPV--------------------------------------------- 154 +UniRef90_C1LZF7 VDLVPSKRFPTN-------------------------------------- 168 +UniRef90_UPI0000E478D2 PAMQQSR------------------------------------------- 174 +UniRef90_UPI0000E49A1C QSVEQWS------------------------------------------- 108 +UniRef90_A8E5T1 CDEEQ--------------------------------------------- 155 +UniRef90_C1C3T6 RDEEE--------------------------------------------- 153 +UniRef90_Q13588 RDEEP--------------------------------------------- 153 +UniRef90_UPI0001C606E3 RDEEP--------------------------------------------- 153 +UniRef90_Q9CX99 CDEQP--------------------------------------------- 153 +UniRef90_UPI0000DA3575 CDEQP--------------------------------------------- 160 +UniRef90_UPI0000D9440A RDEEP--------------------------------------------- 153 +UniRef90_UPI000155C0E1 RDEEQ--------------------------------------------- 153 +UniRef90_UPI0000E80FCB RDDEQ--------------------------------------------- 153 +UniRef90_UPI00016E4BE7 RDPEQ--------------------------------------------- 152 +UniRef90_Q503S8 RDLDH--------------------------------------------- 152 +UniRef90_Q4V9Q1 RDPEG--------------------------------------------- 152 +UniRef90_UPI00017B202F RDPPS--------------------------------------------- 151 +UniRef90_UPI0000E25B42 RDRTREDQGHRGNSLDR---RSQGGPHLSGAVGEEIRPSMNRKLSDHPPT 265 +UniRef90_O75791 RDRTREDQGHRGNSLDR---RSQGGPHLSGAVGEEIRPSMNRKLSDHPPT 192 +UniRef90_B7Z8F8 RDRTREDQGHRGNSLDR---RSQGGPHLSGAVGEEIRPSMNRKLSDHPPT 166 +UniRef90_UPI00005BC6B6 RDRTREEQGQRGNSLDR---RSQGGHPLSGAVGEEIRPSMNRKPSDHP-L 191 +UniRef90_O89100 RDGTQ-DQGHRGNSLDR---RSQGGPHPSGTVGEEIRPSVNRKLSDHLPL 191 +UniRef90_UPI0000EDE7DF RDGTREDQERRGGSLDR---RAQEGLGLGGACGEEIRVPMNRKMSDLHPP 192 +UniRef90_UPI0000F2E19C RDGGREEQDRWGGSLER---RLQEGLHISGGVGEETRPSTNRKQSDHPPA 357 +UniRef90_UPI0000E7F8B9 RDDSREEKERRGGSLER---MSRDGLHVGGAAAEAHS-SMSKRYVDHP-- 189 +UniRef90_UPI0000ECD2B7 RDDSREEKERRGGSLER---MSRDGLHVGGAAAEAHS-SMSKRYVDHPVP 191 +UniRef90_UPI000194E163 RDNSQEEKERHGGSLER---IGREGFHMGGAAGEDHS-SISKRYVEYPIP 206 +UniRef90_B5X487 RDGSRDDQSPSTPQPLKRGSLPEERS-----YGAPTAATSHRRASDLP-- 188 +UniRef90_Q567F1 RDGSGDE--PRAPPPIK--SQPEVRPPPGGGYGSPQTSSQNRSTTDPT-- 189 + diff --git a/examples/surf/test_rsurf.py b/examples/surf/test_rsurf.py deleted file mode 100644 index e8818bdac3f3b8338a53db871608c0871e72d880..0000000000000000000000000000000000000000 --- a/examples/surf/test_rsurf.py +++ /dev/null @@ -1,26 +0,0 @@ -scene.SetFog(False) - -eh = io.LoadEntity("sdh.pdb") -ev = eh.Select("cname=A") -ec=gfx.Entity("p",ev) -ec.SetRenderMode(gfx.CPK) -scene.Add(ec) -scene.SetCenter(ec.GetCenter()) -ec.Hide() - -s = mol.BuildSurface(ev,1.5,15.0/57.3) -gs=gfx.Surface("s",s) -scene.Add(gs) - -# for debug reasons -rs=mol.RSurf(1.5) -for a in ev.GetAtomList(): - rs.AddSphere(a.GetPos(),a.GetRadius(),str(a)) -rs.Build() -rs.Triangulate(60.0*3.1415/180.0) -gr=gfx.RSurface("r",rs) -scene.Add(gr) -gr.Hide() - - - diff --git a/modules/CMakeLists.txt b/modules/CMakeLists.txt index dd418e1c256f3c9dcf0c17d24cd732a693db1c05..20e102235b323e0a3b32e531beef75808129b535 100644 --- a/modules/CMakeLists.txt +++ b/modules/CMakeLists.txt @@ -3,7 +3,8 @@ file(GLOB ALL_FILES *) foreach(fname ${ALL_FILES}) if(NOT ${fname} MATCHES ".*.svn" AND NOT ${fname} MATCHES ".*CMakeFiles" - AND NOT ${fname} MATCHES ".*main") + AND NOT ${fname} MATCHES ".*main" + AND NOT ${fname} MATCHES "doc") if(IS_DIRECTORY ${fname}) add_subdirectory(${fname}) endif() diff --git a/modules/base/doc/base.rst b/modules/base/doc/base.rst new file mode 100644 index 0000000000000000000000000000000000000000..8bec08e983113dffdae61f80ef509ae6fecd9abe --- /dev/null +++ b/modules/base/doc/base.rst @@ -0,0 +1,9 @@ +:mod:`ost.settings` - Locate Files and Retrieve Preferences +================================================================================ + +.. automodule:: ost.settings + :synopsis: Helper Functions to Locate Files and Retrieve Preferences + :members: + + + diff --git a/modules/base/doc/generic.rst b/modules/base/doc/generic.rst new file mode 100644 index 0000000000000000000000000000000000000000..6c2cd34cb6d0a29b75a8a8470c6b07a8f7e67d7d --- /dev/null +++ b/modules/base/doc/generic.rst @@ -0,0 +1,157 @@ +Storing Custom Data +================================================================================ + +Introduction +-------------------------------------------------------------------------------- + +It is often very convenient to store any arbitrary data inside an Entity. A few examples are: + + * calculated properties of atoms + * sequence conservation of a residue + * interaction energy of a substructure with its surrounding + * fit of a fragment inside an electron density map + +In OpenStructure this is supported by the use of generic properties. Most +building blocks are derived from :class:`GenericPropertyContainer`, meaning that +arbitrary key-value pairs can be stored in them. In essence, the following +classes support generic properties: + + * :class:`~mol.EntityHandle` and :class:`~mol.EntityView` + * :class:`~mol.ChainHandle` and :class:`~mol.ChainView` + * :class:`~ResidueHandle` and :class:`~mol.ResidueView` + * :class:`~mol.AtomHandle` and :class:`~mol.AtomView` + * :class:`~mol.BondHandle` + * :class:`~seq.SequenceHandle` and :class:`~seq.AlignmentHandle` + +The view variants will reflect the generic properties of the handle variants. + +A generic property key is always a string, and a value can be one of string, float, int or bool. For each of these data types, methods to retrieve and store values are available both in Python and C++. + +Storing and Accessing Data +-------------------------------------------------------------------------------- + +All OpenStructure building blocks that are :class:`GenericPropContainers`, have +four different methods to store generic data, depending on the data type (i.e. +string, float, int or bool). + +To store a float value with the key 'myfloatprop' in all atoms of an entity: + +.. code-block:: python + + import math + for atom in entity.GetAtomList(): + val=5*math.sin(0.4*atom.GetPos().GetX()) + atom.SetFloatProp("myfloatprop", val) + +If a GenericProp at a given level (i.e. atom, bond, residue, chain or entity) +already exists, it will be overwritten. To check if it exists, use: + +.. code-block:: python + + exists=atom.HasProp("myfloatprop") + print exists + +To access the value of a generic property, we first check if the property exists +and then access it, using the method suitable for the data type of the property. +For the previously set property "myfloatprop" of the data type real, at the atom +level: + +.. code-block:: python + + for atom in entity.GetAtomList(): + if atom.HasProp("myfloatprop"): + print atom.GetFloatProp("myfloatprop") + +When trying to access a property that has not been set, or one that has been +set, but at a different level, an error is thrown. The same is true when trying +to access a property of a different data type, e.g.: + +.. code-block:: python + + # all of the following lines will throw errors + # error because the property does not exist + print atom.GetFloatProp("unknownprop") + + # error because the property was set at another level + print entity.GetFloatProp("myfloatprop") + + # error because the data type of the property is different + print atom.GetStringProp("myfloatprop") + + +Use of Generic Properties in Queries +-------------------------------------------------------------------------------- + +The :doc:`../mol/base/query` can also be used for numeric generic properties (i.e. bool, +int, float), but the syntax is slightly different. To access any generic +properties, it needs to be specified that they are generic and at which level +they are defined. Therefore, all generic properties start with a 'g', followed +by an 'a', 'r' or 'c' for atom, residue or chain level respectively. For more +details see :doc:`../mol/base/query`. + + +API documentation +-------------------------------------------------------------------------------- + +.. class:: GenericPropertyContainer + + .. method:: HasProp(key) + + checks existence of property. Returns true, if the the class contains a + property with the given name, false if not. + + .. method:: GetPropAsString(key) + + Returns the string representation of a property, or the empty String if + the property addressed by key does not exist. Note that this is not the + same as trying to get a generic float/int/bool property as a string type; + the latter will result in a boost:get exception. Use this method to obtain + a representation suitable for output. + + .. method:: GetStringProp(key) + GetStringProp(key, default_value) + + Get string property. The first signature raises a GenericPropError error if + the property does not exist, the second returns the default value. + + + .. method:: GetFloatProp(key) + GetFloatProp(key, default_value) + + Get float property. The first signature raises a GenericPropError error if + the property does not exist, the second returns the default value. + + + .. method:: GetIntProp(key) + GetIntProp(key, default_value) + + Get int property. The first signature raises a GenericPropError error if + the property does not exist, the second returns the default value. + + .. method:: GetBoolProp(key) + GetBoolProp(key, default_value) + + Get bool property. The first signature raises a GenericPropError error if + the property does not exist, the second returns the default value. + + .. method:: ClearProps() + + Remove all generic properties + + + .. method:: SetStringProp(key, value) + + Set string property, overriding an existing property with the same name + + .. method:: SetFloatProp(key, value) + + Set float property, overriding an existing property with the same name + + .. method:: SetIntProp(key, value) + + Set int property, overriding an existing property with the same name + + .. method:: SetBoolProp(key, value) + + Set bool property, overriding a property with the same name + diff --git a/modules/base/pymod/CMakeLists.txt b/modules/base/pymod/CMakeLists.txt index 4eb36a9147d7d83b081d05f4abeb3ca0a2868467..22700288ae061f64b45fb741e13b5044b2bf8977 100644 --- a/modules/base/pymod/CMakeLists.txt +++ b/modules/base/pymod/CMakeLists.txt @@ -7,4 +7,4 @@ set(OST_BASE_PYMOD_SOURCES pymod(NAME base OUTPUT_DIR ost CPP ${OST_BASE_PYMOD_SOURCES} - PY __init__.py settings.py) + PY __init__.py settings.py stutil.py) diff --git a/modules/base/pymod/__init__.py b/modules/base/pymod/__init__.py index 3d2137f7e76f6a66a8cf2041319d801742fafedf..aa723917bec0aed0d90e3c682ff200c39e90b72a 100644 --- a/modules/base/pymod/__init__.py +++ b/modules/base/pymod/__init__.py @@ -17,6 +17,7 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #------------------------------------------------------------------------------ from _base import * +from stutil import * from ost import geom from ost import io diff --git a/modules/base/pymod/export_logger.cc b/modules/base/pymod/export_logger.cc index b385742e744fea3f056ec84db24317ac1038d748..deefb408cc5fe33e755cff1f08be05c30a206984 100644 --- a/modules/base/pymod/export_logger.cc +++ b/modules/base/pymod/export_logger.cc @@ -39,7 +39,7 @@ void pop_verb() Logger::Instance().PopVerbosityLevel(); } -void log_error(const String& m) {LOGN_MESSAGE(m);} +void log_error(const String& m) {LOGN_ERROR(m);} void log_message(const String& m) {LOGN_MESSAGE(m);} void log_verbose(const String& m) {LOGN_VERBOSE(m);} void log_debug(const String& m) {LOGN_DEBUG(m);} diff --git a/modules/base/pymod/settings.py b/modules/base/pymod/settings.py index 1740c3287dace8d503aa93f801c763ba9384dfa5..29814963710f83b36736464f229701ea153df243 100644 --- a/modules/base/pymod/settings.py +++ b/modules/base/pymod/settings.py @@ -3,12 +3,13 @@ import __main__ def GetValue(val_key,val_default=None,prefix='OST'): - ''' + """ Returns the value of the variable val_key if defined, otherwise returns the default value provided by the user (if provided). Search order: - 1) environment variable called $prefix_$val_key - 2) variable called val_key in .dngrc file - ''' + + * environment variable called $prefix_$val_key + * variable called val_key in .ostrc file + """ if prefix: env_var_name='%s_%s' % (prefix, val_key) else: @@ -24,6 +25,12 @@ def GetValue(val_key,val_default=None,prefix='OST'): return val_default class FileNotFound(RuntimeError): + """ + Raised when :func:`Locate` is unable to locate a file. The exception contains + detailed information on what was tried to locate the file, i.e. search paths, + environment variables and also provides useful hints on how to let Locate know + where to find the file. + """ def __init__(self, name, reason): self.name=name self.reason=reason @@ -33,21 +40,23 @@ class FileNotFound(RuntimeError): def Locate(file_name, explicit_file_name=None, search_paths=[], env_name=None, search_system_paths=True): """ - Helper function to locate files. To get the full name of - an executable, let's say qmake, use + Helper function to locate files. To get the full name of an executable, let's + say qmake, use + + .. code-block:: python - abs_qmake_path=Locate('qmake', env_name='QMAKE_EXECUTABLE') + abs_qmake_path=Locate('qmake', env_name='QMAKE_EXECUTABLE') - First the function checks if an environment variable with the - name QMAKE_EXECUTABLE is set. If so, the value of this variable - is returned. Next, each directory listed in search_paths is - searched. If the executable could still not be found and - search_system_paths is set to True, the binary search paths are - searched. + First the function checks if an environment variable with the name + QMAKE_EXECUTABLE is set. If so, the value of this variable is returned. Next, + each directory listed in search_paths is searched. If the executable could + still not be found and search_system_paths is set to True, the binary search + paths are searched. - If the file could not be located, a FileNotFound exception will be raised - containing a detail description why Locate failed. The error message is - formatted in such a way that it can directly be presented to the user. + If the file could not be located, a :exc:`~ost.settings.FileNotFound` + exception will be raised containing a detail description why Locate failed. The + error message is formatted in such a way that it can directly be presented to + the user. """ if type(file_name) is str: file_names=[file_name] diff --git a/modules/base/pymod/stutil.py b/modules/base/pymod/stutil.py new file mode 100644 index 0000000000000000000000000000000000000000..2f64beaefa3731c5689c73c585cbc3edb37d32f1 --- /dev/null +++ b/modules/base/pymod/stutil.py @@ -0,0 +1,95 @@ +import math +from ost import mol + +def FloatValueExtract(func): + """ + Decorator to wrap functions that take a list of float values. In addition to + passing in a list of float values directly, it is possible to extract the + values from attributes or generic properties. + """ + def _dec(xs, prop=None, attr=None): + if prop!=None: + if len(xs)==0: + return func([]) + assert attr==None + level=mol.Prop.Level.UNSPECIFIED + if isinstance(xs[0], mol.AtomBase): + level=mol.Prop.Level.ATOM + elif isinstance(xs[0], mol.ResidueBase): + level=mol.Prop.Level.RESIDUE + elif isinstance(xs[0], mol.ChainBase): + level=mol.Prop.Level.CHAIN + epm=mol.EntityPropertyMapper(prop, level) + vals=[] + for x in xs: + try: + vals.append(epm.Get(x)) + except: + pass + return func(vals) + if attr!=None: + vals=[] + for x in xs: + try: + vals.append(getattr(x, attr)) + except: + pass + return func(vals) + return func(xs) + return _dec + +@FloatValueExtract +def Mean(xs): + """ + Calculate mean of dataset + """ + if len(xs)==0: + raise RuntimeError("Can't calculate mean of empty sequence") + return sum(xs)/len(xs) + +@FloatValueExtract +def StdDev(xs): + """ + Calculate standard-deviation of dataset + + | sum[xi-<x>]^2 | + sigma=sqrt|---------------| + | n | + """ + mean=Mean(xs) + return math.sqrt(sum([(x-mean)**2 for x in xs])/len(xs)) + +@FloatValueExtract +def Min(xs): + return min(xs) + +@FloatValueExtract +def Max(xs): + return max(xs) + +def Correl(xs, ys): + """ + Calculates the correlation coefficient between xs and ys as + + sum[(xi-<x>)*(yi-<y>)] + r=---------------------- + (n-1)*sx*sy + + where <x>, <y> are the mean of dataset xs and ys, and, sx and sy are the + standard deviations. + """ + if len(xs)!=len(ys): + raise RuntimeError("Can't calculate correl. Sequence lengths do not match.") + if len(xs)==1: + raise RuntimeError("Can't calculate correl of sequences with length 1.") + mean_x=Mean(xs) + mean_y=Mean(ys) + sigma_x, sigma_y=(0.0, 0.0) + cross_term=0.0 + for x, y in zip(xs, ys): + cross_term+=(x-mean_x)*(y-mean_y) + sigma_x+=(x-mean_x)**2 + sigma_y+=(y-mean_y)**2 + sigma_x=math.sqrt(sigma_x/len(xs)) + sigma_y=math.sqrt(sigma_y/len(ys)) + return cross_term/((len(xs)-1)*sigma_x*sigma_y) diff --git a/modules/base/pymod/wrap_base.cc b/modules/base/pymod/wrap_base.cc index c3dd609ecfcaca8ba873cf6d83a49f30c27c12cc..13bc81155762468dd32565533f847b5db999d129 100644 --- a/modules/base/pymod/wrap_base.cc +++ b/modules/base/pymod/wrap_base.cc @@ -20,6 +20,7 @@ #include <boost/python.hpp> #include <boost/python/suite/indexing/vector_indexing_suite.hpp> +#include <ost/export_helper/vector.hh> #include <ost/base.hh> #include <ost/platform.hh> @@ -38,8 +39,19 @@ BOOST_PYTHON_MODULE(_base) export_Logger(); export_Range(); export_Units(); + typedef std::vector<float> FloatList; + class_<FloatList>("FloatList", init<>()) + .def(vector_indexing_suite<FloatList>()) + .def(ost::VectorAdditions<FloatList>()) + ; class_<std::vector<String> >("StringList", init<>()) .def(vector_indexing_suite<std::vector<String> >()) + ; + + typedef std::vector<int> IntList; + class_<std::vector<int> >("IntList", init<>()) + .def(vector_indexing_suite<std::vector<int> >()) + .def(ost::VectorAdditions<IntList>()) ; } diff --git a/modules/base/src/CMakeLists.txt b/modules/base/src/CMakeLists.txt index ecdc389dbea1db9239f5aa92dc4152554938005d..3ca08186ac38dd5b8a6a563338ba7278d4610d1d 100644 --- a/modules/base/src/CMakeLists.txt +++ b/modules/base/src/CMakeLists.txt @@ -1,13 +1,12 @@ set(OST_BASE_SOURCES generic_property.cc -invalid_handle.cc -integrity_error.cc log.cc profile.cc units.cc string_ref.cc platform.cc message.cc +test_utils/compare_files.cc ) set(OST_BASE_HEADERS @@ -31,8 +30,14 @@ fixed_string.hh tri_matrix.hh ) +set(OST_EXPORT_HELPERS +generic_property_def.hh +pair_to_tuple_conv.hh +vector.hh +) module(NAME base SOURCES ${OST_BASE_SOURCES} - HEADERS generic_property_def.hh IN_DIR export_helper ${OST_BASE_HEADERS} + HEADERS ${OST_EXPORT_HELPERS} IN_DIR export_helper + compare_files.hh IN_DIR test_utils ${OST_BASE_HEADERS} DEPENDS_ON geom HEADER_OUTPUT_DIR ost) diff --git a/modules/base/src/export_helper/pair_to_tuple_conv.hh b/modules/base/src/export_helper/pair_to_tuple_conv.hh new file mode 100644 index 0000000000000000000000000000000000000000..eba6ebd9b1ebbdbd7723d6ebaee656d0121e02d8 --- /dev/null +++ b/modules/base/src/export_helper/pair_to_tuple_conv.hh @@ -0,0 +1,37 @@ +//------------------------------------------------------------------------------ +// This file is part of the OpenStructure project <www.openstructure.org> +// +// Copyright (C) 2008-2010 by the OpenStructure authors +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation; either version 3.0 of the License, or (at your option) +// any later version. +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +//------------------------------------------------------------------------------ +#include <boost/python.hpp> + +namespace ost { + +/// \brief helper to convert between python tuple and std::pair +/// +/// Usage: +/// +/// register_to_python_converter<PairToTupleConverter<T1, T2>, +/// std::pair<T1, T2>>() +template<class T1, class T2> +struct PairToTupleConverter { + static PyObject* convert(const std::pair<T1, T2>& pair) { + boost::python::tuple t=boost::python::make_tuple<T1,T2>(pair.first, + pair.second); + return boost::python::incref(t.ptr()); + } +}; +} \ No newline at end of file diff --git a/modules/base/src/export_helper/vector.hh b/modules/base/src/export_helper/vector.hh new file mode 100644 index 0000000000000000000000000000000000000000..0b262bf5561aac5523112c0ad34cd2c4b4e0e776 --- /dev/null +++ b/modules/base/src/export_helper/vector.hh @@ -0,0 +1,46 @@ +#ifndef OST_EXPORT_HELPER_VECTOR_HH +#define OST_EXPORT_HELPER_VECTOR_HH + +# include <boost/python/def_visitor.hpp> + +/* + Author: Marco Biasini + */ + +namespace ost { + + +template <typename Container> +class VectorAdditions : + public boost::python::def_visitor<VectorAdditions<Container> > { +public: + template <class Class> + void visit(Class& cl) const + { + cl + .def("__str__", &to_string) + ; + } +private: + static std::string to_string(Container& cl) + { + std::stringstream ss; + ss << "["; + bool first=true; + for (typename Container::const_iterator + i=cl.begin(), e=cl.end(); i!=e; ++i) { + if (first) { + first=false; + } else { + ss << ", "; + } + ss << (*i); + } + ss << "]"; + return ss.str(); + } +}; + +} + +#endif diff --git a/modules/base/src/integrity_error.hh b/modules/base/src/integrity_error.hh index 45c4e263c12c65f4fe4adf019acd0bcb518894cc..ba3271faeea9034bd6af4f23a752adb031e3eef8 100644 --- a/modules/base/src/integrity_error.hh +++ b/modules/base/src/integrity_error.hh @@ -25,9 +25,11 @@ namespace ost { -class DLLEXPORT_OST_BASE IntegrityError : public Error { +class DLLEXPORT IntegrityError : public Error { public: - IntegrityError(const String& msg); + IntegrityError(const String& msg): + Error(msg) + { } }; } diff --git a/modules/base/src/invalid_handle.hh b/modules/base/src/invalid_handle.hh index 03814ef7b726c3e9137e97cd08bf886039d33bb2..fdb56203edf1b126aad19d06be3e0b070c2a29bd 100644 --- a/modules/base/src/invalid_handle.hh +++ b/modules/base/src/invalid_handle.hh @@ -27,9 +27,11 @@ namespace ost { /// \brief Signals access of member functions of invalid handles -class DLLEXPORT_OST_BASE InvalidHandle : public Error { +class DLLEXPORT InvalidHandle : public Error { public: - InvalidHandle(); + InvalidHandle() + : Error("Can not access invalid handle or view") + {} }; template <typename H> diff --git a/modules/base/src/pod_vector.hh b/modules/base/src/pod_vector.hh index 34a7299e978f3127a58db122b95543ee84ec697f..a4da274b7f3d77da393fd803e74242a5986146e5 100644 --- a/modules/base/src/pod_vector.hh +++ b/modules/base/src/pod_vector.hh @@ -34,7 +34,7 @@ namespace ost { /// \brief vector container that treats its data as POD - even if it isn't in /// the strict sense. template <typename T> -class DLLEXPORT_OST_BASE PodVector { +class TEMPLATE_DEF_EXPORT PodVector { public: PodVector(): begin_(NULL), end_(NULL), capacity_(NULL) {} typedef T value_type; diff --git a/modules/base/src/test_utils/compare_files.cc b/modules/base/src/test_utils/compare_files.cc new file mode 100644 index 0000000000000000000000000000000000000000..76243902178b665dce748da031c906a33105ae97 --- /dev/null +++ b/modules/base/src/test_utils/compare_files.cc @@ -0,0 +1,55 @@ +//------------------------------------------------------------------------------ +// This file is part of the OpenStructure project <www.openstructure.org> +// +// Copyright (C) 2008-2010 by the OpenStructure authors +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation; either version 3.0 of the License, or (at your option) +// any later version. +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +//------------------------------------------------------------------------------ + +#include <iostream> +#include <fstream> +#include "compare_files.hh" + +namespace ost { +bool compare_files(const String& test, const String& gold_standard) +{ + std::ifstream test_stream(test.c_str()); + std::ifstream gold_stream(gold_standard.c_str()); + String test_line, gold_line; + while (true) { + bool test_end=std::getline(test_stream, test_line) != 0; + bool gold_end=std::getline(gold_stream, gold_line) != 0; + if (!(test_end || gold_end)) { + return true; + } + if (!test_end) { + std::cerr << gold_standard << " contains additional line(s):" + << std::endl << gold_line; + return false; + } + if (!gold_end) { + std::cerr << test << " contains additional line(s):" + << std::endl << test_line; + return false; + } + if (gold_line!=test_line) { + std::cerr << "line mismatch:" << std::endl << "test: " << test_line + << std::endl << "gold: " << gold_line; + return false; + } + } + return true; +} + +} diff --git a/modules/base/src/invalid_handle.cc b/modules/base/src/test_utils/compare_files.hh similarity index 80% rename from modules/base/src/invalid_handle.cc rename to modules/base/src/test_utils/compare_files.hh index 86a631ad5f1c687e9d81249c03984fe0b17cf085..8944e080592d6f3ca79efd0016e3362b187c2660 100644 --- a/modules/base/src/invalid_handle.cc +++ b/modules/base/src/test_utils/compare_files.hh @@ -16,15 +16,18 @@ // along with this library; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA //------------------------------------------------------------------------------ -#include <ost/message.hh> -#include "invalid_handle.hh" +#ifndef OST_COMPARE_FILES_HH +#define OST_COMPARE_FILES_HH + +#include <ost/base.hh> +#include <ost/module_config.hh> namespace ost { -InvalidHandle::InvalidHandle() - : Error("Can not access invalid handle or view") { - +bool DLLEXPORT_OST_BASE compare_files(const String& test, + const String& gold_standard); } -} + +#endif diff --git a/modules/bindings/pymod/msms.py b/modules/bindings/pymod/msms.py index a7a3dd13eb2be594c69f0fb368c941ce403dfd7a..7f9e089ffe63b92f036fe35151593205b25ae6c9 100644 --- a/modules/bindings/pymod/msms.py +++ b/modules/bindings/pymod/msms.py @@ -144,7 +144,10 @@ def CalculateSurfaceArea(entity, density=1.0, radius=1.5, all_surf=False, # parse selection if no_hydrogens: - selection+=" and ele!=H" + if selection=="": + selection="ele!=H" + else: + selection+=" and ele!=H" # setup files for msms (msms_data_dir, msms_data_file)=_SetupFiles(entity, selection) @@ -215,7 +218,10 @@ def CalculateSurface(entity, density=1.0, radius=1.5, all_surf=False, # parse selection if no_hydrogens: - selection+=" and ele!=H" + if selection=="": + selection="ele!=H" + else: + selection+=" and ele!=H" # setup files for msms diff --git a/modules/bindings/tests/test_msms.py b/modules/bindings/tests/test_msms.py index 54c1ab5b82ded72b14ede0d4c49195306dbdcd22..8cd56ee5a5b8577ba2c82a39e408bc01c60a4617 100755 --- a/modules/bindings/tests/test_msms.py +++ b/modules/bindings/tests/test_msms.py @@ -32,4 +32,7 @@ if __name__ == "__main__": except(settings.FileNotFound): print "Could not find msms executable: ignoring unit tests" exit(0) - unittest.main() + try: + unittest.main() + except Exception, e: + print e diff --git a/modules/config/CMakeLists.txt b/modules/config/CMakeLists.txt index e8f153cff4742e75e969ffc25ab6223c8ed95f4e..ddf07651188d815e51ae669972981c4aeab469c1 100644 --- a/modules/config/CMakeLists.txt +++ b/modules/config/CMakeLists.txt @@ -55,3 +55,4 @@ configure_file(config.hh.in ${CONFIG_HH_FILE}) add_custom_target(ost_config) stage_headers("${OST_CONFIG_HEADERS}" "ost" "ost_config" "" "ost") +install(FILES ${OST_CONFIG_HEADERS} DESTINATION include/ost) diff --git a/modules/config/base.hh b/modules/config/base.hh index 2e279e89d30524c0212fefca649902310b70f050..d119fb8ce4d6737ad2b1e1b471b5147d95003712 100644 --- a/modules/config/base.hh +++ b/modules/config/base.hh @@ -80,7 +80,7 @@ inline Real rint(Real d) #pragma warning(disable:4244) #pragma warning(disable:4231) #pragma warning(disable:4305) - +#pragma warning(disable:4351) // turn off "new behavior ... will be default initialized" warning #ifndef log2_function #define log2_function diff --git a/modules/conop/doc/conop.rst b/modules/conop/doc/conop.rst index fb65ee1ad4e33a27ecf0ba0b9e50851531b8be72..a7ebe2eaa24fd6cb3c6f2990e9ba939b77644544 100644 --- a/modules/conop/doc/conop.rst +++ b/modules/conop/doc/conop.rst @@ -1,7 +1,7 @@ -:mod:`conop` -- Connectivity and Topology of Molecules +:mod:`~ost.conop` -- Connectivity and Topology of Molecules ================================================================================ -.. module:: conop +.. module:: ost.conop :synopsis: The conop modules implement different strategies to derive connectivity information of molecules. diff --git a/modules/conop/src/chemdict_tool.cc b/modules/conop/src/chemdict_tool.cc index 79b36b7b1dd6c29397bdf8cc31753488e15ff348..865425d8c75a7b3a9437f38d0bd753dc783ee465 100644 --- a/modules/conop/src/chemdict_tool.cc +++ b/modules/conop/src/chemdict_tool.cc @@ -140,12 +140,23 @@ public: } else if (item.GetName()==StringRef("pdbx_modified_date", 18)) { compound_->SetModificationDate(conop::Date::FromString(item.GetValue())); } + } else if (item.GetName()==StringRef("atom_id", 7)) { + atom_.name=item.GetValue().str(); + } else if (item.GetName()==StringRef("alt_atom_id", 11)) { + atom_.alt_name=item.GetValue().str(); + } else if (item.GetName()==StringRef("type_symbol", 11)) { + atom_.element=item.GetValue().str(); + } else if (item.GetName()==StringRef("pdbx_ordinal", 12)) { + atom_.ordinal=item.GetValue().to_int().second-1; } } virtual void OnEndData() { if (insert_) { + if (compound_->GetAtomSpecs().empty()) { + compound_->AddAtom(atom_); + } lib_->AddCompound(compound_); } } @@ -176,6 +187,7 @@ private: static std::map<String, mol::ChemClass> tm_; std::map<String, int> atom_map_; LoopType loop_type_; + conop::AtomSpec atom_; }; std::map<String, mol::ChemClass> ChemDictParser::tm_=std::map<String, mol::ChemClass>(); diff --git a/modules/conop/src/compound_lib.cc b/modules/conop/src/compound_lib.cc index 073ea0606fdc7c0d23257b6f4e6ba9c11c08e8fc..a5c9ad1a77455341a3e466cf0447a0d8bd1cccac 100644 --- a/modules/conop/src/compound_lib.cc +++ b/modules/conop/src/compound_lib.cc @@ -256,7 +256,7 @@ void CompoundLib::LoadAtomsFromDB(CompoundPtr comp, int pk) { atom_sp.alt_name=String(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1))); atom_sp.element=String(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 2))); atom_sp.ordinal=sqlite3_column_int(stmt, 3); - atom_sp.is_leaving=bool(sqlite3_column_int(stmt, 4)); + atom_sp.is_leaving=bool(sqlite3_column_int(stmt, 4)!=0); comp->AddAtom(atom_sp); } } diff --git a/modules/conop/src/conop.cc b/modules/conop/src/conop.cc index e634b6a7386159b0d0dba1895a44526b9acbcc89..3267e83e059ecffbeb3490ea18a01994ad5d8599 100644 --- a/modules/conop/src/conop.cc +++ b/modules/conop/src/conop.cc @@ -41,28 +41,28 @@ Conopology::Conopology(): builder_map_["DEFAULT"]=builder_map_["HEURISTIC"]; ele_rad_map_["H"] = 1.09; - + ele_rad_map_["C"] = 1.75; ele_rad_map_["N"] = 1.55; ele_rad_map_["O"] = 1.52; ele_rad_map_["F"] = 1.47; - - ele_rad_map_["Na"] = 2.27; - ele_rad_map_["Mg"] = 1.73; - ele_rad_map_["Si"] = 2.10; + + ele_rad_map_["NA"] = 2.27; + ele_rad_map_["MG"] = 1.73; + ele_rad_map_["SI"] = 2.10; ele_rad_map_["P"] = 1.80; ele_rad_map_["S"] = 1.80; - ele_rad_map_["Cl"] = 1.75; - + ele_rad_map_["CL"] = 1.75; + ele_rad_map_["K"] = 2.75; - ele_rad_map_["Ca"] = 2.00; - ele_rad_map_["Mn"] = 2.00; - ele_rad_map_["Fe"] = 2.00; - ele_rad_map_["Co"] = 2.00; - ele_rad_map_["Ni"] = 1.63; - ele_rad_map_["Cu"] = 1.40; - ele_rad_map_["Zn"] = 1.39; - ele_rad_map_["Br"] = 1.85; + ele_rad_map_["CA"] = 2.00; + ele_rad_map_["MN"] = 2.00; + ele_rad_map_["FE"] = 2.00; + ele_rad_map_["CO"] = 2.00; + ele_rad_map_["NI"] = 1.63; + ele_rad_map_["CU"] = 1.40; + ele_rad_map_["ZN"] = 1.39; + ele_rad_map_["BR"] = 1.85; ele_rad_map_["I"] = 1.98; @@ -70,122 +70,122 @@ Conopology::Conopology(): // Element masses according to IUPAC standards // see http://www.chem.qmul.ac.uk/iupac/AtWt/ ele_mass_map_["H"] = 1.00794; - ele_mass_map_["He"] = 4.002602; - ele_mass_map_["Li"] = 6.941; - ele_mass_map_["Be"] = 9.012182; + ele_mass_map_["HE"] = 4.002602; + ele_mass_map_["LI"] = 6.941; + ele_mass_map_["BE"] = 9.012182; ele_mass_map_["B"] = 10.811; ele_mass_map_["C"] = 12.0107; ele_mass_map_["N"] = 14.0067; ele_mass_map_["O"] = 15.9994; ele_mass_map_["F"] = 18.9984032; - ele_mass_map_["Ne"] = 20.1797; - ele_mass_map_["Na"] = 22.98976928; - ele_mass_map_["Mg"] = 24.3050; - ele_mass_map_["Al"] = 26.9815386; - ele_mass_map_["Si"] = 28.0855; + ele_mass_map_["NE"] = 20.1797; + ele_mass_map_["NA"] = 22.98976928; + ele_mass_map_["MG"] = 24.3050; + ele_mass_map_["AL"] = 26.9815386; + ele_mass_map_["SI"] = 28.0855; ele_mass_map_["P"] = 30.973762; ele_mass_map_["S"] = 32.065; - ele_mass_map_["Cl"] = 35.453; - ele_mass_map_["Ar"] = 39.948; + ele_mass_map_["CL"] = 35.453; + ele_mass_map_["AR"] = 39.948; ele_mass_map_["K"] = 39.0983; - ele_mass_map_["Ca"] = 40.078; - ele_mass_map_["Sc"] = 44.955912; - ele_mass_map_["Ti"] = 47.867; + ele_mass_map_["CA"] = 40.078; + ele_mass_map_["SC"] = 44.955912; + ele_mass_map_["TI"] = 47.867; ele_mass_map_["V"] = 50.9415; - ele_mass_map_["Cr"] = 51.9961; - ele_mass_map_["Mn"] = 54.938045; - ele_mass_map_["Fe"] = 55.845; - ele_mass_map_["Co"] = 58.933195; - ele_mass_map_["Ni"] = 58.6934; - ele_mass_map_["Cu"] = 63.546; - ele_mass_map_["Zn"] = 65.38; - ele_mass_map_["Ga"] = 69.723; - ele_mass_map_["Ge"] = 72.64; - ele_mass_map_["As"] = 74.92160; - ele_mass_map_["Se"] = 78.96; - ele_mass_map_["Br"] = 79.904; - ele_mass_map_["Kr"] = 83.798; - ele_mass_map_["Rb"] = 85.4678; - ele_mass_map_["Sr"] = 87.62; + ele_mass_map_["CR"] = 51.9961; + ele_mass_map_["MN"] = 54.938045; + ele_mass_map_["FE"] = 55.845; + ele_mass_map_["CO"] = 58.933195; + ele_mass_map_["NI"] = 58.6934; + ele_mass_map_["CU"] = 63.546; + ele_mass_map_["ZN"] = 65.38; + ele_mass_map_["GA"] = 69.723; + ele_mass_map_["GE"] = 72.64; + ele_mass_map_["AS"] = 74.92160; + ele_mass_map_["SE"] = 78.96; + ele_mass_map_["BR"] = 79.904; + ele_mass_map_["KR"] = 83.798; + ele_mass_map_["RB"] = 85.4678; + ele_mass_map_["SR"] = 87.62; ele_mass_map_["Y"] = 88.90585; - ele_mass_map_["Zr"] = 91.224; - ele_mass_map_["Nb"] = 92.90638; - ele_mass_map_["Mo"] = 95.96; - ele_mass_map_["Tc"] = 98.0; - ele_mass_map_["Ru"] = 101.07; - ele_mass_map_["Rh"] = 102.90550; - ele_mass_map_["Pd"] = 106.42; - ele_mass_map_["Ag"] = 107.8682; - ele_mass_map_["Cd"] = 112.411; - ele_mass_map_["In"] = 114.818; - ele_mass_map_["Sn"] = 118.710; - ele_mass_map_["Sb"] = 121.760; - ele_mass_map_["Te"] = 127.60; + ele_mass_map_["ZR"] = 91.224; + ele_mass_map_["NB"] = 92.90638; + ele_mass_map_["MO"] = 95.96; + ele_mass_map_["TC"] = 98.0; + ele_mass_map_["RU"] = 101.07; + ele_mass_map_["RH"] = 102.90550; + ele_mass_map_["PD"] = 106.42; + ele_mass_map_["AG"] = 107.8682; + ele_mass_map_["CD"] = 112.411; + ele_mass_map_["IN"] = 114.818; + ele_mass_map_["SN"] = 118.710; + ele_mass_map_["SB"] = 121.760; + ele_mass_map_["TE"] = 127.60; ele_mass_map_["I"] = 126.90447; - ele_mass_map_["Xe"] = 131.293; - ele_mass_map_["Cs"] = 132.9054519; - ele_mass_map_["Ba"] = 137.327; - ele_mass_map_["La"] = 138.90547; - ele_mass_map_["Ce"] = 140.116; - ele_mass_map_["Pr"] = 140.90765; - ele_mass_map_["Nd"] = 144.242; - ele_mass_map_["Pm"] = 145.0; - ele_mass_map_["Sm"] = 150.36; - ele_mass_map_["Eu"] = 151.964; - ele_mass_map_["Gd"] = 157.25; - ele_mass_map_["Tb"] = 158.92535; - ele_mass_map_["Dy"] = 162.500; - ele_mass_map_["Ho"] = 164.93032; - ele_mass_map_["Er"] = 167.259; - ele_mass_map_["Tm"] = 168.93421; - ele_mass_map_["Yb"] = 173.054; - ele_mass_map_["Lu"] = 174.9668; - ele_mass_map_["Hf"] = 178.49; - ele_mass_map_["Ta"] = 180.94788; + ele_mass_map_["XE"] = 131.293; + ele_mass_map_["CS"] = 132.9054519; + ele_mass_map_["BA"] = 137.327; + ele_mass_map_["LA"] = 138.90547; + ele_mass_map_["CE"] = 140.116; + ele_mass_map_["PR"] = 140.90765; + ele_mass_map_["ND"] = 144.242; + ele_mass_map_["PM"] = 145.0; + ele_mass_map_["SM"] = 150.36; + ele_mass_map_["EU"] = 151.964; + ele_mass_map_["GD"] = 157.25; + ele_mass_map_["TB"] = 158.92535; + ele_mass_map_["DY"] = 162.500; + ele_mass_map_["HO"] = 164.93032; + ele_mass_map_["ER"] = 167.259; + ele_mass_map_["TM"] = 168.93421; + ele_mass_map_["YB"] = 173.054; + ele_mass_map_["LU"] = 174.9668; + ele_mass_map_["HF"] = 178.49; + ele_mass_map_["TA"] = 180.94788; ele_mass_map_["W"] = 183.84; - ele_mass_map_["Re"] = 186.207; - ele_mass_map_["Os"] = 190.23; - ele_mass_map_["Ir"] = 192.217; - ele_mass_map_["Pt"] = 195.084; - ele_mass_map_["Au"] = 196.966569; - ele_mass_map_["Hg"] = 200.59; - ele_mass_map_["Tl"] = 204.3833; - ele_mass_map_["Pb"] = 207.2; - ele_mass_map_["Bi"] = 208.98040; - ele_mass_map_["Po"] = 209.0; - ele_mass_map_["At"] = 210.0; - ele_mass_map_["Rn"] = 222.0; - ele_mass_map_["Fr"] = 223.0; - ele_mass_map_["Ra"] = 226.0; - ele_mass_map_["Ac"] = 227.0; - ele_mass_map_["Th"] = 232.03806; - ele_mass_map_["Pa"] = 231.03588; + ele_mass_map_["RE"] = 186.207; + ele_mass_map_["OS"] = 190.23; + ele_mass_map_["IR"] = 192.217; + ele_mass_map_["PT"] = 195.084; + ele_mass_map_["AU"] = 196.966569; + ele_mass_map_["HG"] = 200.59; + ele_mass_map_["TL"] = 204.3833; + ele_mass_map_["PB"] = 207.2; + ele_mass_map_["BI"] = 208.98040; + ele_mass_map_["PO"] = 209.0; + ele_mass_map_["AT"] = 210.0; + ele_mass_map_["RN"] = 222.0; + ele_mass_map_["FR"] = 223.0; + ele_mass_map_["RA"] = 226.0; + ele_mass_map_["AC"] = 227.0; + ele_mass_map_["TH"] = 232.03806; + ele_mass_map_["PA"] = 231.03588; ele_mass_map_["U"] = 238.02891; - ele_mass_map_["Np"] = 237.0; - ele_mass_map_["Pu"] = 244.0; - ele_mass_map_["Am"] = 243.0; - ele_mass_map_["Cm"] = 247.0; - ele_mass_map_["Bk"] = 247.0; - ele_mass_map_["Cf"] = 251.0; - ele_mass_map_["Es"] = 252.0; - ele_mass_map_["Fm"] = 257.0; - ele_mass_map_["Md"] = 258.0; - ele_mass_map_["No"] = 259.0; - ele_mass_map_["Lr"] = 262.0; - ele_mass_map_["Rf"] = 267.0; - ele_mass_map_["Db"] = 268.0; - ele_mass_map_["Sg"] = 271.0; - ele_mass_map_["Bh"] = 272.0; - ele_mass_map_["Hs"] = 270.0; - ele_mass_map_["Mt"] = 276.0; - ele_mass_map_["Ds"] = 281.0; - ele_mass_map_["Rg"] = 280.0; - ele_mass_map_["Cn"] = 285.0; - ele_mass_map_["Uut"]= 284.0; - ele_mass_map_["Uuq"]= 289.0; - ele_mass_map_["Uup"]= 288.0; - ele_mass_map_["Uuh"]= 293.0; - ele_mass_map_["Uuo"]= 294.0; + ele_mass_map_["NP"] = 237.0; + ele_mass_map_["PU"] = 244.0; + ele_mass_map_["AM"] = 243.0; + ele_mass_map_["CM"] = 247.0; + ele_mass_map_["BK"] = 247.0; + ele_mass_map_["CF"] = 251.0; + ele_mass_map_["ES"] = 252.0; + ele_mass_map_["FM"] = 257.0; + ele_mass_map_["MD"] = 258.0; + ele_mass_map_["NO"] = 259.0; + ele_mass_map_["LR"] = 262.0; + ele_mass_map_["RF"] = 267.0; + ele_mass_map_["DB"] = 268.0; + ele_mass_map_["SG"] = 271.0; + ele_mass_map_["BH"] = 272.0; + ele_mass_map_["HS"] = 270.0; + ele_mass_map_["MT"] = 276.0; + ele_mass_map_["DS"] = 281.0; + ele_mass_map_["RG"] = 280.0; + ele_mass_map_["CN"] = 285.0; + ele_mass_map_["UUT"]= 284.0; + ele_mass_map_["UUQ"]= 289.0; + ele_mass_map_["UUP"]= 288.0; + ele_mass_map_["UUH"]= 293.0; + ele_mass_map_["UUO"]= 294.0; } void Conopology::RegisterBuilder(const BuilderP& b, const String& name) { @@ -294,13 +294,18 @@ void Conopology::ConnectAll(const BuilderP& b, mol::EntityHandle eh, int flag) Real Conopology::GetDefaultAtomRadius(const String& element) const { - std::map<String,Real>::const_iterator it = ele_rad_map_.find(element); + String upper_ele=element; + std::transform(upper_ele.begin(),upper_ele.end(),upper_ele.begin(),toupper); + std::map<String,Real>::const_iterator it = ele_rad_map_.find(upper_ele); return it==ele_rad_map_.end() ? 1.5 : it->second; } Real Conopology::GetDefaultAtomMass(const String& element) const { - std::map<String,Real>::const_iterator it = ele_mass_map_.find(element); + String upper_ele=element; + std::transform(upper_ele.begin(),upper_ele.end(),upper_ele.begin(),toupper); + + std::map<String,Real>::const_iterator it = ele_mass_map_.find(upper_ele); return it==ele_mass_map_.end() ? 1.0 : it->second; } diff --git a/modules/conop/src/heuristic_builder.cc b/modules/conop/src/heuristic_builder.cc index 5c27610eaa153c19c58ff6b51c68bb0fa23871a4..644771764b9325a8601cf56e54615c711e12cea1 100644 --- a/modules/conop/src/heuristic_builder.cc +++ b/modules/conop/src/heuristic_builder.cc @@ -418,7 +418,13 @@ void HeuristicBuilder::FillResidueProps(mol::ResidueHandle residue) { residue.SetChemClass(mol::ChemClass(ret.first.GetChemClass())); residue.SetOneLetterCode(ret.first.GetOneLetterCode()); } else { - residue.SetChemClass(mol::ChemClass(mol::ChemClass::Unknown)); + if (residue.FindAtom("N") && residue.FindAtom("CA") && + residue.FindAtom("C") && residue.FindAtom("O")) { + residue.SetChemClass(mol::ChemClass(mol::ChemClass::LPeptideLinking)); + } else { + residue.SetChemClass(mol::ChemClass(mol::ChemClass::Unknown)); + } + residue.SetOneLetterCode('?'); } diff --git a/modules/doc/external.rst b/modules/doc/external.rst new file mode 100644 index 0000000000000000000000000000000000000000..7ea3b22db79befda28b9a262e95a91cd64b26d6d --- /dev/null +++ b/modules/doc/external.rst @@ -0,0 +1,111 @@ +Using External Programs within OpenStructure +================================================================================ + +Introduction +-------------------------------------------------------------------------------- + +It is often very useful to use external programs to do a specific task. In principle, this can be done by writing out files from OpenStructure and manually running an external program, however, for convenience, this can also be done directly from within OpenStructure using Python commands. + +This tutorial will give you some hints how to do this for a new external program. The process basically consists of four steps: + + * locate the executable of the external program + * prepare all necessary files + * execute the external program from python + * read in generated output + + +Locating the Executable +-------------------------------------------------------------------------------- + +There is a helper function available to locate files, and especially executables: :func:`~ost.settings.Locate`. Using this, you can obtain the full path of an executable. + +As an example, we would like to obtain the full path of the msms executable (a program to calculate molecular surfaces): + +.. code-block:: python + + from ost import settings + exe_path=settings.Locate('msms', search_paths=['/opt/app','/home/app'], + env_name='MSMS', search_system_paths=True) + print exe_path + +The :func:`~ost.settings.Locate` command looks for the program with the name +`msms`. If env_name is set, it first looks if an environment variable with the +name `MSMS` is set. If not, all paths in search_paths are searched. If the +executable could still not be found and search_system_paths is set to True, the +binary search paths are searched. If the executable could not be found, a +:exc:`~ost.FileNotFound` exception is raised with a detailed description where +Locate was searching for the executable. + +Prepare All Files +-------------------------------------------------------------------------------- + +The preparation of the necessary files is very dependent on the external program. Often it is useful to generate a temporary directory or file. For this, the python module tempfile is very handy. + +An example how to generate a temporary directory, open a file in this directory and write the position and radius of all atoms into this file is shown here: + +.. code-block:: python + + import tempfile + import os + + # generate a temporary directory + tmp_dir_name=tempfile.mkdtemp() + print 'temporary directory:',tmp_dir_name + + # generate and open a file in the temp directory + tmp_file_name=os.path.join(tmp_dir_name,"entity") + tmp_file_handle=open(tmp_file_name, 'w') + print 'temporary file:',tmp_file_handle + + # write position and radius of all atoms to file + for a in entity.GetAtomList(): + position=a.GetPos() + tmp_file_handle.write('%8.3f %8.3f %8.3f %4.2f\n' % (position[0], + position[1], position[2], a.GetProp().radius)) + + # close the file + tmp_file_handle.close() + +Execute the External Program +-------------------------------------------------------------------------------- + +The external program can be executed from python using the python module subprocess. + +To run the external program msms from the above example, with the temporary file generated before, we can use the following: + +.. code-block:: python + + import subprocess + + # set the command to execute + command="%s -if %s -of %s" % (exe_path, + tmp_file_name, tmp_file_name) + print 'command:',command + + # run the executable with the command + proc = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE) + stdout_value, stderr_value = proc.communicate() + + #check for successful completion of msms + if proc.returncode!=0: + print "WARNING: msms error\n", stdout_value + raise subprocess.CalledProcessError(proc.returncode, command) + + # print everything written to the command line (stdout) + print stdout_value + +Read Generated Output +-------------------------------------------------------------------------------- + +The last step includes reading of generated files (like in the case of msms) and/or processing of the generated command line output. + +Here we first print the command line output and then load the generated msms surface and print the number of vertex points: + +.. code-block:: python + + # print everything written to the command line (stdout) + print stdout_value + + # read msms surface from file + surface=io.LoadSurface(tmp_file_name, "msms") + print 'number of vertices:',len(surface.GetVertexIDList()) diff --git a/modules/doc/install.rst b/modules/doc/install.rst new file mode 100644 index 0000000000000000000000000000000000000000..86c10f7c515fd9b98f12ebbb595f0fb8b561e053 --- /dev/null +++ b/modules/doc/install.rst @@ -0,0 +1,108 @@ +Installing OpenStructure +================================================================================ + +This document describes how to install OpenStructure from source. If you are not planning to develop code for OpenStructure, you might be better off with one of the binaries available for download. + +Installing the Dependencies +-------------------------------------------------------------------------------- + +OpenStructure uses a bunch of OpenSource libraries. If you haven't already installed them, please install them now! + + * `CMake <http://cmake.org>`_ + * `Eigen2 <http://eigen.tuxfamily.org>`_ + * `Boost <http://boost.org>`_ + * `libpng <http://www.libpng.org>`_ + * `Python <http://python.org>`_ + * `Qt <http://qt.nokia.com>`_ + +When you enable support for image processing, you will need: + + * `FFTW3 <http://fftw.org>`_. By default, OpenStructure is compiled with single precision and thus also requires FFTW to be compiled with single precision. Most platforms offer this as a second package. If you are compiling manually, use the `--enable-single` option. + + * `libtiff <http://www.libtiff.org>`_ + + + +If you would like to use the graphical user interface, also install: + + * `SIP <http://www.riverbankcomputing.co.uk/software/sip/download>`_. + * `PyQt4 <http://www.riverbankcomputing.co.uk/software/pyqt/download>`_. + +In case you are compiling under Windows you have to install `Visualstudio +2008 <http://www.microsoft.com/express/Downloads>`_. to compile the dependecies +and OpenStructure. We recommend to compile the dependecies manually. Enter the +directories where the dependencies are located in Tools->Options->Projects and +Solutions->VC++ directories. Choose 'bin' directories to enter program paths to +cmake, qmake and python, 'lib' directories to point to the location(s) of your +dependencies. + +Checking out the Source +-------------------------------------------------------------------------------- + +You can checkout the source from SVN. The repository is located at + + https://dng.biozentrum.unibas.ch/svn/openstructure/trunk + +If you are using the commandline client, type in your shell + + svn co https://ost.biozentrum.unibas.ch/svn/openstructure/trunk + +On Windows install svn clients like `tortoisesvn <http://tortoisesvn.tigris.org>`_ and use the function 'checkout' then enter the above mention URL. + + +Configuring +-------------------------------------------------------------------------------- + + +OpenStructure uses `CMake <http://cmake.org>`_ for compiling and building the project. The next required step is to configure the build environment using cmake. You can do that by invoking `cmake` in the project directory (On Windows choose Tools->visualstudio commandline prompt from within visualstudio) : + + cmake . <options> + +There are two kinds of options: Options that let you control the building behaviour, enabling and disabling the compilation of certain modules and options that let you tell CMake where to find the dependencies. All of them are passed to CMake with via `-D<opt>=<value>`. + +Flag to choose build system +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +On Windows make sure you specify -G"Visual Studio 9 2008"! + +Flags to Control the Dependencies +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +By default, `CMake <http://cmake.org>`_ searches the standard directories for dependencies. However, on some systems, this might not be enough. Here is a short description of how CMake figures out what dependencies to take and how you can influence it. + + * Boost is mainly controlled via the `BOOST_ROOT` option. If boost wasn't + found, it should be set to the prefix of the boost installation. + + * `QT_QMAKE_EXECUTABLE` defines the exact Qt installation to take. It should + be set to the full path to `qmake`. + + * `PYTHON_ROOT` is the Python equivalent of BOOST_ROOT. It should be set to + the prefix path containing the python binary, headers and libraries. + + * `SYS_ROOT` controls the general prefix for searching libraries and headers. + By default, it is set to `/`. + +Build Options +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + * `ENABLE_UI` controls whether to build the graphical user interface module. By + default it is set to true. + * `ENABLE_IMG` controls whether to build the image processing module. This will + enable support for density maps, and general image processing in 1, 2 an 3 + dimensions. By default it is set to true. + + * `ENABLE_GFX` controls whether to build the graphics module. By default, this + is set to true. If set to none, this implies `ENABLE_UI=NO`. + + * Shader support is controlled with `USE_SHADER`. By default, no shaders are + used. + + * If `OPTIMIZE` is set to 1, an optimized version of OpenStructure is built. + +Building the Project +-------------------------------------------------------------------------------- + +Type `make`. If you are using a multi-core machine, you can use the `-j` flag to run +multiple jobs at once. + +On Windows run 'Build OpenStructure' from the build menu. diff --git a/modules/doc/intro.rst b/modules/doc/intro.rst new file mode 100644 index 0000000000000000000000000000000000000000..abf6e6cf9fe1ac349a9af1a8d5fd63c686bf14b9 --- /dev/null +++ b/modules/doc/intro.rst @@ -0,0 +1,368 @@ +A gentle introduction to OpenStructure +================================================================================ + +In this tutorial you will be learning by example how to use the OpenStructure +framework. + +We assume that you already have a version of OpenStructure installed. If not, +please refer to :doc:`install`. + + +What will be covered in this tutorial? +-------------------------------------------------------------------------------- + +This tutorial is aimed at users that would like to get their hands dirty and +execute commands in Python and write scripts rather clicking their way through a +shiny user interface. The user interface of OpenStructure is in a very early +state anyway that you probably won't go far by clicking you way through... + +The first part of the tutorial is a walk-through of the basic functionality you +will be using in your everyday work. You will learn how to load structure +datasets, inspect, display them in the 3D window and save them. + + +Getting ready to rumble +-------------------------------------------------------------------------------- + +The files we will be using in the tutorial are available in the examples folder +that comes with OpenStructure. Depending on your platform, the examples are +located at a different location: + + * on *MacOS X* the files are in /Applications/OpenStructure/Examples + * on *Linux* and *Windows* PREFIX/share/openstructure/examples, where PREFIX is + the path to the directory containing OpenStructure. + +Starting DNG +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The graphical user interface of OpenStructure is called DNG (Dino/DeepView Next +Generation). To start it, + + * on *MacOS X* double click DNG.app in /Applications/OpenStructure + * on *Windows* double click dng.bat inside the PREFIX/bin directory + * on *Linux* fire up a terminal change into the OpenStructure installation + directory and type 'bin/dng'. If you have the binary directory in the PATH, + typing dng is sufficient. + +Interactive Python Shell +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Now we will enter commands in the Python Shell (in the screenshot above, the +python shell is located at the bottom of the main window). If you want to get +more information on any object, function or class, the python help command may +be useful. For example: + + .. code-block:: python + + # get list of methods of EntityView + help(mol.EntityView) + # get help for method Select + help(mol.EntityView.Select) + +Loading and inspecting a protein structure +-------------------------------------------------------------------------------- + +OpenStructure has a module that is dedicated to deal with input and output of +data, including sequence alignment formats, protein structures and density data +and images. If you are reading this tutorial you most certainly have dealt with +protein structures before and you are most certainly aware that they are usually +stored in Brookhaven structure files (aka PDB files). The official name for +molecules stored in a PDB file is an entity. You will hear this word all the +time, but you can replace the word entity with molecule in your head. + + +To load a PDB file, type + + .. code-block:: python + + fragment=io.LoadPDB('/path/to/examples/entity/fragment.pdb') + +This will load the fragment from the specified file 'fragment.pdb' and store the result in fragment. For more information on the LoadPDB function, type + + .. code-block:: python + + help(io.LoadPDB) + +Now let's inspect what we just loaded: + + .. code-block:: python + + print fragment.chain_count + print fragment.residue_count + print fragment.atom_count + +As you can see, our fragment consists of one peptide chain of 12 amino acids and +has 81 atoms in total. Now let's examine our fragment in more detail. Enter the +command + + .. code-block:: python + + for residue in fragment.residues: + print residue + +This will print a list of all residues in the fragment. Similarly to get a list +of atoms, use: + + .. code-block:: python + + for atom in fragment.atoms: + print atom + +Of course, we can also get a list of atoms grouped by residues: + + .. code-block:: python + + for residue in fragment.residues: + print residue, 'has', residue.atom_count, 'atom(s).' + for atom in residue.atoms: + print ' ', atom.name, atom.pos + +And, for completeness, we will first group them by chain, then by residues. + + .. code-block:: python + + for chain in fragments.chains: + print 'chain', chain.name, 'has', chain.residue_count, 'residue(s)' + for residue in chain.residues: + print ' ', residue, 'has', residue.atom_count, 'atom(s).' + for atom in residue.atoms: + print ' ', atom.name, atom.pos + +Aah, wait! A protein fragment would not be complete without bonds: Let's see +what bonds we have in there: + + .. code-block:: python + + for bond in fragment.bonds: + print bond + +From these short code examples we already see how the entity is structured: On +one hand we have a hierarchy of chains, residues and atoms. On the other hand, +we have bonds that form a network overlayed on the hierarchy. This is +illustrated in the picture on the left. An important feature of entities is that +we can always assume that the hierarchy is intact. You will never find an atom +without residues, no residue can exist without a parent chain and chains belong +always to an entity. + +Let There Be Shiny Graphics +-------------------------------------------------------------------------------- + +For visually inspecting the fragment, we now create a graphical representation +of the entity: + + .. code-block:: python + + go=gfx.Entity("Fragment", fragment) + scene.Add(go) + scene.CenterOn(go) + +Now you will see the fragment in the 3D window (left): + + + +Use the mouse to rotate, zoom in an shift the camera. Double clicking on an atom will center the camera on that atom. + +Introduction to Views +-------------------------------------------------------------------------------- + +Often during processing and visualisation of data, only parts of a protein +structure are of interest. This realisation has had a major impact on the design +of OpenStructure and is tied very deeply into the core of the framework. +Subparts of structure are modeled as so-called :class:`EntityViews +<mol.EntityView>`. You can think of them as a selection of chains, residues, +atoms and bonds of an entity. A views has almost the same interface as the +underlying entity, making it very easy to mix entity views with handles in +Python due to the dynamic nature of the language. An algorithm that is written +for entities will almost always (with some care) also work for +:class:`EntityHandles <mol.EntityHandle>`. This is referred to as `duck-typing +<http://en.wikipedia.org/wiki/Duck_typing>`_ (I don' t care if it is a duck as +long as it looks like a duck), a concept used all over the place in Python. + +A typical view can be seen in the image on the left. The view consists of one +chain, one residue and two atoms. Again the same rule applies: No atom can be +part of the view without it's residue. In this example, no bonds are included, +since there is at most one atom per bond in the original structure. + +To familiarize yourself with the concept of views, we will use the fragment in +the 3D window. + +We will use several ways to select parts of our fragment: + * By using a dedicated query language + * By manually constructing a view + +The Query Language +-------------------------------------------------------------------------------- + +The first way to select parts of a structure is with a dedicated mini-language, +called ["the query language”](docs/tut/query.html). In the Python Shell, type + + .. code-block:: python + + go.selection=fragment.Select('') + +A green halo will be displayed around the selected parts (image in the middle). + +As you can see the previous statement created a “full view”, containing all the +chains, residues, atoms and bonds. To select lysine residues, type + + .. code-block:: python + + go.selection=fragment.Select('rname=LYS') + + +As you can see (image in the middle), the only lysine residue is now +highlighted in the 3D window, because it was the only one matching the predicate +"residue name must be equal to LYS". Several such predicates can be combined +with boolean operators such as *and* and *or*. To select residues with residue +number 1 to 3, the following statement will do the job: + + .. code-block:: python + + go.selection=fragment.Select('rnum>=1 and rnum<=3') + +but this is very cumbersome. That's why there is a shortcut to this statement. +You can specify a range of values. + + .. code-block:: python + + go.selection=fragment.Select('rnum=1:3') + +For a complete description of what you can do with the query language, have a +look at the :doc:`../mol/base/query`. + + +Constructing Views Manually +-------------------------------------------------------------------------------- + +Sometimes the query language Is Not Enough (TM). For these cases the +construction of manual entities becomes neccessary. This is pretty straight +forward: + + .. code-block:: python + + view=fragment.CreateEmptyView() + ca=fragment.FindAtom('A', mol.ResNum(1), 'CA') + cb=fragment.FindAtom('A', mol.ResNum(1), 'CB') + view.AddAtom(ca) + view.AddAtom(cb) + go.SetSelection(view) + +The last step sets our constructed view as the current selection, displaying it +in the 3D window. As you can see, C-alpha and C-beta of the first residue are +not connected by bonds, even though both atoms are in the view. You have either +to add the bond manually with + + .. code-block:: python + + ca_cb=ca.FindBondToAtom(cb) + view.AddBond(ca_cb) + +Or as a very convenient shortcut 'view.AddAllInclusiveBonds()' to add all bonds +that have both bonding partners in the view. + +Don't forget to call update the selection of the graphics object to see what +view you have created. + +Saving an Entity +-------------------------------------------------------------------------------- + +Saving an entity (or a view) is a breeze: + +Type + + .. code-block:: python + + io.SavePDB(fragment, 'full.pdb') + +to save the full view. To save only the backbone atoms, we can first select the +backbone atoms and then save it: + + .. code-block:: python + + io.SavePDB(fragment.Select('aname=CA,C,N,O'), 'backbone.pdb') + + +Loading images and density maps +-------------------------------------------------------------------------------- + +Openstructure features a :mod:`~ost.img` module that is dedicated to the +manipulation of +images/density maps. The images or density maps can either be one-, two- or +three-dimensional. The most common formats used in x-ray and electron +crystallography and atomic force microscope are supported in addition to several +general purpose image formats. See `supported file formats` for details. +The :mod:`~ost.img` module was originally developed as part of the Image +Processing Library & Toolbox IPLT. More documentation and examples can also be +found on the `IPLT website <http://www.iplt.org>`_. + +To load a density map, type + + .. code-block:: python + + map=io.LoadImage('/path/to/examples/map/1ppt.map') + +This will load the fragment density map from the specified file 'fragment.map' +and store the result in fragment_map. + +Now let's inspect what we just loaded: + + .. code-block:: python + + print map.GetPixelSampling() + +We can see that the sampling is set to 1.0 Angstroems in all three dimensions. + +Manipulating images and density maps +-------------------------------------------------------------------------------- + +The algorithms used for manipulation of an image are found in the +:mod:`~ost.img` module. Therefore before using an algorithm we first have to +import the :mod:`~ost.img` module. + + .. code-block:: python + + from ost import img + + +The :mod:`~ost.img` module provides a wide range of algorithm to manipulate +image data. Here for the example we use a LowPassFilter to restrict the +resolution of the density map. + + .. code-block:: python + + map_filtered=map.Apply(img.alg.LowPassFilter(3.0)) + +The filtered map is stored in a new variable called fragment\_map\_filtered. + + +Displaying images and density maps +-------------------------------------------------------------------------------- + +Now that we have a filtered map it's time to have a look at it. There are +fundamentally two ways to visualize 3-dimensional density maps. One is by +drawing isosurfaces. These are conceputally similar to contour lines used in +cartography: every point on an isosurface has the same density value. +Isosurfaces are easy to create in OpenStructure: + + .. code-block:: python + + go=gfx.MapIso("filtered", map_filtered,0.5) + scene.Add(go) + +The other way to visualize a 3-dimensional map is by showing one 2-dimensional +density slice at a time, allowing the user to move through the slices. In +OpenStructure this is achieved using a DataViewer docs/tut/imgdataviewer.html). +A DataViewer showing the filtered map is created using the following command: + + .. code-block:: python + + gui.CreateDataViewer(map_filtered) + +This command displays a panel showing one slice of the density map lying on a +particular (x,y) plane in the coordinate reference system. +The 'z' and 'x' keys can be used to move to slices lying at a lower or higher +coordinate along the 'z' axis, allowing the examination of +the full 3-dimensional volume. + +A more detailed explanation of the :mod:`~ost.img` module can be found in the +tutorial section for :mod:`~ost.img`. diff --git a/modules/doc/newmodule.rst b/modules/doc/newmodule.rst new file mode 100644 index 0000000000000000000000000000000000000000..a45283055f5a4e60af1f468b5846857d7c3c28c1 --- /dev/null +++ b/modules/doc/newmodule.rst @@ -0,0 +1,301 @@ +Creating a New Module +================================================================================ + +OpenStructure can be extended by writing additional modules. A module will +usually consist of a set of C++ classes and methods, most of which will also be +exported to Python. It is also possible to write modules completely in Python. + +The build system of OpenStructure is quite simple. The main difference to other +projects is the use of a so-called stage directory. The stage directory +replicates the normal layout of a standard Linux directory structure, with an +'include' directory for the headers, a 'lib' directory containing the shared +library files, a `bin` directory for the executables and a 'share' directory +for the platform-independent data like icons, images and examples. + +OpenStructure uses `CMake <http://www.cmake.org>`_ to build the project. The +rules for the build-system are defined in `CMakeLists.txt` files. When running +`CMake <http://cmake.org>`_, the files are compiled and copied into stage. The +real installation, if necessary, happens at a later stage. This is referred to +as staging of the files. + +If a new module is written following the guidelines in this page, it will be +seamlessly included in the build system and will then be available form both +the DNG python console and the OpenStructure command line as any other native +module. + +As a first step, a new directory structure must be created to accommodate the +new module. + +Directory Structure +-------------------------------------------------------------------------------- + +For the purpose of this example, let's assume we are creating a new module +called 'mod' (for 'modeling'). Let's create a directory named `mod` under the +'modules' directory in the OpenStructure development tree, and populate it with +the three subdirectories `src`, `pymod`, and `tests`. Then we add a +`CMakeLists.txt` file in the 'mod' directory, consisting of three lines: + +.. code-block:: bash + + add_subdirectory(src) + add_subdirectory(pymod) + add_subdirectory(tests) + +The Module Code +-------------------------------------------------------------------------------- + +In the `src` subdirectory we put the code that implements the functionality of +the new module, plus a `config.hh` header file. + +Here is a skeleton of one of the files in the directory , `modeling_new_class.hh`: + +.. code-block:: cpp + + #ifndef OST_MOD_NEW_CLASS_H + #define OST_MOD_NEW_CLASS_H + + #include <ost/mod/module_config.hh> + + // All other necessary includes go here + + namespace ost { namespace mod { + + class DLLEXPORT_OST_MOD NewClass { + public: + void NewMethod(); + + // All declarations of NewClass go here + + }; + + }} // namespaces + + #endif + +And here is the skeleton of the corresponding `modeling_new_class.cc` file: + +.. code-block:: cpp + + #include "modeling_new_class.hh" + + using namespace ost::mol; + using namespace ost::mod; + + // All other necessary includes and namespace directives + // go here + + void NewClass::NewMethod(): + { + // Implementation + } + + // Implementation code for NewClass goes here + +Obviously, the `src` directory can contain many files, each implementing classes +and functions that will end up in the module. In order to build and stage +the module shared library, a `CMakeLists.txt` file needs to be written for the +`src` directory: + +.. code-block:: bash + + set(OST_MOD_SOURCES + modeling_new_class.cc + // All other source files + ) + + set(OST_MOD_HEADERS + modeling_new_class.hh + // All other header files + ) + + module(NAME mod SOURCES "${OST_MOD_SOURCES}" + HEADERS ${OST_MOD_HEADERS} + DEPENDS_ON mol mol_alg) + + +The line containing the `DEPENDS_ON` directive lists all the modules on which +the new module depends (in this case :mod:`mol` and :mod:`ost.mol.alg`). The +`module` macro will take care of staging the headers, in this case into +`ost/mod` and compiling, linking and staging of a library with the name +`libost_mod.so` (`libost_gmod.dylib` on MacOS X). + +.. note:: + + Due to a limitation in the built-int install command of CMake, for modules + that have their headers in several directories, it is required to group the + headers by directory, leading to a call of module like: + +.. code-block:: bash + + module(NAME mol SOURCES atom_handle.cc impl/atom_impl.cc + HEADERS atom_impl.hh IN_DIR impl + atom_handle.hh) + +The `module_config.hh` header is required for each module to setup the +environment on Windows: Each public class, method and function needs to marked +with `DLLEXPORT` or `DLLIMPORT` to teach the linker where to look for the +symbol. The correct use of either `DLLIMPORT` and `DLLEXPORT` is depending on +the context: While compiling a header file that is part of the same shared +library, `DLLEXPORT` must be used. When compiling a header that is part of +an external shared library, `DLLIMPORT` must be used. A typical module_config +header looks like this: + +.. code-block:: cpp + + #ifndef OST_MOD_MODULE_CONFIG_HH + #define OST_MOD_MODULE_CONFIG_HH + + #include <ost/base.hh> + + #if defined(OST_MODULE_OST_MOD) + # define DLLEXPORT_OST_MOD DLLEXPORT + #else + # define DLLEXPORT_OST_MOD DLLIMPORT + #endif + #endif + +The Testing Framework +-------------------------------------------------------------------------------- + +The `tests` directory contains code for unit tests. The code is compiled and +executed when one invokes compilation using the 'make check' command. Tests are +run by means of the `Boost Unitests Library +<http://www.boost.org/doc/libs/1_37_0/libs/test/doc/html/index.html>`_, which is +used throughout OpenStructure. Before coding the test routines, the required +skeleton needs to be put in place. + +The main code is put into 'tests.cc', which will become the test executable: + +.. code-block:: cpp + + #include <boost/test/unit_test.hpp> + using boost::unit_test_framework::test_suite; + + #include "test_modeling.hh" + + test_suite* + unit_unit_test_suite( int argc, char * argv[] ) { + std::auto_ptr<test_suite> test(BOOST_TEST_SUITE( "Module Mod Test" )); + + test->add(CreateModelingTest()); + + return test.release(); + } + + +The most relevant line adds the test suite for the new module to the global test +list. The test suite is created by the factory function CreateModelingTest(), +which is declared in the `test_modeling.hh` header file. + +.. code-block:: cpp + + #ifndef OST_MOD_TEST_MODELING_H + #define OST_MOD_TEST_MODELING_H + + #include <boost/test/unit_test.hpp> + using boost::unit_test_framework::test_suite; + + test_suite* CreateModelingTest(); + + #endif + +The definition of the factory function is found in the actual test code, +which we put in `test_modeling.cc`. Here is a skeleton version of that file: + +.. code-block:: cpp + + #include "test_modeling.hh" + + // additional include statements will go here + + namespace test_modeling { + + void test() + { + // test code will go here + } + + } + + test_suite* CreateModelingTest() + { + using namespace test_modeling; + test_suite* ts=BOOST_TEST_SUITE("Modeling Test"); + ts->add(BOOST_TEST_CASE(&test)); + + return ts; + } + +In this file, all the normal Boost Test Library macros and functions can be used. (For example `BOOST_CHECK`, `BOOST_FAIL`, etc.) + +Here is finally the build script skeleton that needs to be put into +`mod/tests/`: + +.. code-block:: bash + + set(OST_MOD_UNIT_TESTS + tests.cc + test_modeling.cc + ) + + ost_unittest(mod "${OST_MOD_UNIT_TESTS}") + target_link_libraries(ost_mol ost_mol_alg ost_mod) + +In the last line the call to the 'target\_link\_libraries' function contains the +names of the modules on which the 'mod' unit test code depends (in this case, +the :mod:`mol` and :mod:`ost.mol.alg` modules), in addition to the `mod` module +itself. + +The Python Wrapper +-------------------------------------------------------------------------------- + +Finally, the module API is exported to Python using the `Boost Python +Library <http://www.boost.org/doc/libs/1_37_0/libs/python/doc/index.html>`_. +In `mod/pymod`, the wrapper code for the classes in the new module is put into a +file named `wrap\_mod.cc`: + +.. code-block:: cpp + + #include <boost/python.hpp> + using namespace boost::python; + + #include <ost/mod/modeling_new_class.hh> + + using namespace ost::mol; + using namespace ost::mod; + + // All other necessary includes and namespace directives + // go here + + BOOST_PYTHON_MODULE(_mod) + { + class_<NewClass>("NewClass", init<>() ) + .def("NewMethod", &NewClass::NewMethod) + ; + + // All other Boost Python code goes here + } + +The `mod/pymod` directory must obviously contain a `CMakeLists.txt` file: + +.. code-block:: bash + + set(OST_MOD_PYMOD_SOURCES + wrap_mod.cc + ) + + pymod(NAME mod OUTPUT_DIR ost/mod + CPP ${OST_MOD_PYMOD_SOURCES} PY __init__.py) + +The directory should also contain an `__init.py__` file with the +following content: + +.. code-block:: python + + from _mod import * + +In case one wants to implement Python-only functionality for the new module, any +number of function definitions can be added to the `__init.py__` file. + +That's it!. The next time the OpenStructure project is compiled, the new module +will be built and made available at both the C++ and the Python level. diff --git a/modules/geom/doc/composite.rst b/modules/geom/doc/composite.rst new file mode 100644 index 0000000000000000000000000000000000000000..0271a206bc9d82d42a7661a58a3ab73deac27f2f --- /dev/null +++ b/modules/geom/doc/composite.rst @@ -0,0 +1,529 @@ +Geometric Objects +================================================================================ + +.. currentmodule:: ost.geom + +Geometrical Objects in Two Dimensions +-------------------------------------------------------------------------------- + +.. class:: Line2() + Line2(from, to) + + Parametric line in two dimensions as defined by an origin and a normalized + direction vector. The first constructor creates a line with origin (0,0) and + direction along the x axis. The second signature creates a line originating + from `from` and pointing towards `to`. + + .. method:: At(t) + + Returns the point on the line at (signed) distance t from origin. + + :param t: free parameter + :type t: float + :rtype: :class:`Vec2` + + + .. method:: GetOrigin() + + Returns the origin of the line: Also available as :attr:`origin`. + + :rtype: :class:`Vec2` + + .. method:: GetDirection() + + Returns the normalized direction vector. Also available as + :attr:`direction`. + + :rtype: :class:`Vec2` + + .. attribute:: direction + + .. attribute:: origin + + +.. class:: Rectangle2() + Rectangle2(top_left, bottom_right) + + Axis aligned rectangle. The first signature creates a rectangle with top-left + corner (-1, -1) and bottom-right corner (1, 1), wheras the second method + allows to set the top-left and bottom-right corners directly. + + :type top_left: :class:`Vec2` + :param top_left: The top-left corner + :param bottom_right: The bottom-right corner + :type bottom_right: :class:`Vec2` + + .. method:: GetWidth() + + Returns the width of the rectangle. Also available as :attr:`width`. + + .. method:: GetHeight() + + Returns the height of the rectangle. Also available as :attr:`height`. + + .. attribute:: width + + :type: float + + .. attribute:: height + + :type: float + + .. method:: GetStart() + + Get top-left corner + + :rtype: :class:`Vec2` + + .. method:: GetEnd() + + Get bottom-right corner + + :rtype: :class:`Vec2` + + .. method:: SetStart(top_left) + + Set top-left corner, leaving the bottom-right corner untouched. + + .. method:: SetEnd(bottom_right) + + Set the bottom-right corner, leaving the top-left corner untouched. + +.. class:: Circle2() + Circle2(circle) + Circle2(center, radius) + + The first signature creates a circle centered at (0, 0) and radius 1.0. The + second signature creates a circle with the same paramters as `circle`. The + third signature creates a new circle with given center and radius. + + .. method:: SetCenter(center) + + Set center of circle + + :type center: :class:`Vec2` + :param center: The new center + + .. method:: SetRadius(radius) + + Set radius of circle + + :type radius: float + :param center: The new radius + + .. method:: GetCenter() + + Returns the center of the circle + + .. method:: GetRadius() + + Returns the radius of the circle + + .. method:: GetArea() + + Returns the area of the circle + + .. method:: GetCircumference() + + Returns the circumference of the circle + + +.. class:: Ellipse2() + Ellipse2(center, a, b, gamma) + + An ellipse is defined by a center, two principal axis and gamma that + defines the angle between the first principal axis an the x-axis. + + .. method:: At(t) + + ? + + .. method:: AtAngle(angle) + + ? + + .. method:: GetBoundingBox() + + Returns the bounding rectangle (axis-aligned) of the ellipse + + :rtype: :class:`Rectangle2` + + + .. method:: GetA() + + Returns the first principal-axis + + .. method:: GetB() + + Returns the second principal-axis + + .. method:: GetGamma() + + Returns the angle of the first principal axis to the x-axis + + .. method:: GetArea() + + Returns the area of the ellipse + + .. method:: GetOrigin() + + Returns the center of the ellipse + + .. method:: SetA(a) + + Set the length of the first principal axis + + .. method:: SetB(b) + + Set the length of the second principal axis + + .. method:: SetGamma(gamma) + + Set the angle of the first principal axis to the x-axis + + .. method:: SetOrigin(ori) + + Set the center of the ellipse + +Geometrical Objects in Three Dimensions +------------------------------------------------------------------------------- + +.. class:: Line3() + Line3(from, to) + + Parametric line in three dimensions as defined by an origin and a normalized + direction vector. The first constructor creates a line with origin (0,0) and + direction along the x axis. The second signature creates a line originating + from `from` and pointing towards `to`. + + .. method:: At(t) + + Returns the point on the line at (signed) distance t from origin. + + :param t: free parameter + :type t: float + :rtype: :class:`Vec3` + + + .. method:: GetOrigin() + + Returns the origin of the line: Also available as :attr:`origin`. + + :rtype: :class:`Vec3` + + .. method:: GetDirection() + + Returns the normalized direction vector. Also available as + :attr:`direction`. + + :rtype: :class:`Vec3` + + .. attribute:: direction + + :type: :class:`Vec3` + + .. attribute:: origin + + :type: :class:`Vec3` + +.. class:: Plane() + Plane(p1, p2, p3) + Plane(x, y, z, p) + Plane(line, point) + Plane(point, normal) + + A plane in 3d-space. The plane can be constructed by either passing in 3 + points (p1, p2, p3), a normal and a point, the four parameters that define the + implicit plane equation (`x`, `y`, `z`, `p`) or a line and a point. + + .. method:: GetNormal() + + Returns the normal of the plane. Also available as :attr:`normal` + + :rtype: :class:`Vec3` + + .. method:: GetP() + + Returns the plane offset, i.e. the projection of any point on the plane onto + the normal. Also available as :attr:`p`. + + :rtype: float + + .. method:: GetOrigin() + + Get the origin of the plane. Also available as :attr:`origin`. + + :rtype: :class:`Vec3` + + .. attribute:: origin + + :type: :class:`Vec3` + .. attribute:: normal + + :type: :class:`Vec3` + + .. attribute:: p + + :type: float + + +.. class:: Sphere() + Sphere(center, radius) + + Represents a sphere in 3d space. The first constructor creates a sphere with + radius 1, centered at (0, 0, 0), the second allows you to set the radius and + center directly. + + :param center: The center + :type center: :class:`Vec3` + :param radius: The radius + :type radius: float + + .. attribute:: radius + + The radius of the sphere. Read-write. Also available as :meth:`GetRadius`, + :meth:`SetRadius`. + + :type: float + + .. attribute:: origin + + The center of the sphere. Read-write. Also available as :meth:`GetOrigin`, + :meth:`SetOrigin`. + + :type: :class:`Vec3` + + .. method:: GetOrigin() + + See :attr:`origin` + + .. method:: SetOrigin(origin) + + See :attr:`origin` + + .. method:: GetRadius() + + See :attr:`radius` + + .. method:: SetRadius(radius) + + See :attr:`radius` + +.. class:: AlignedCuboid(min, max) + + Axis aligned cuboid is a cuboid whose axes are aligned to the x-, y-, and z- + axes of the coordinate system. For arbitrarily oriented bounding cuboid + class, see :class:`Cuboid`. + + .. method:: GetMin() + + Get minimum coordinate, i.e. the lower bound of x-, y-, and z for + any point in the cuboid + + :rtype: :class:`Vec3` + + .. method:: GetMax() + + Get maximum coordinate, i.e. the upper bound of x-, y-, and z for + any point in the cuboid. + + :rtype: :class:`Vec3` + +.. class:: CuboidAxis() + CuboidAxis(dir, half_extent) + + A cuboid axis is defined by a half-extent, and a direction vector. This class + is used in together with the :class:`Cuboid` class. + + :param dir: Direction vector, will be normalized + :type dir: :class:`Vec3` + :param half_extent: The half extent + :type half_extent: float + + .. attribute:: vector + + The normalized direction vector of the cuboid axis. Also available as + :meth:`GetVector` + + :type: :class:`Vec3` + + .. attribute:: half_extent + + The half extent of the cuboid axis is the magnitude of the cuboid + axis measured from the center to the corner. Also available as + :meth:`GetHalfExtent` + + :type: float + + .. attribute:: extent + + The extent of the cuboid axis. This value is always twice the + :attr:`half_extent`. Read-only. Also available as + :meth:`GetExtent`. + + :type: float + + .. method:: GetHalfExtent() + + See :attr:`half_extent` + .. method:: GetExtent() + + See :attr:`extent` + + .. method:: GetVector() + + See :attr:`vector` + +.. class:: Cuboid(center, axis_a, axis_b, axis_c) + + An arbitrarily oriented cuboid defined by a center and 3 axis. The 3 cuboid + axis are stored in the order they are passed to the constructor. This means, + that there is no guarantee that the 3 axes form a right-handed coordinate + system. If a right-handed coordinate system is a requirement, you have to + ensure this on your own: + + .. code-block:: python + + center=... + axis_a=geom.CuboidAxis(...) + axis_b=geom.CuboidAxis(...) + axis_c=geom.CuboidAxis(geom.Cross(axis_a.vector, axis_b.vector), ...) + + cuboid=geom.Cuboid(center, axis_a, axis_b, axis_c) + + :param center: The center + :type center: :class:`Vec3` + :param axis_a: The first axis + :type axis_a: :class:`CuboidAxis` + :param axis_b: The second axis + :type axis_b: :class:`CuboidAxis` + :param axis_c: The third axis + :type axis_c: :class:`CuboidAxis` + + .. attribute:: center + + The center of the cuboid. + + :type: :class:`Vec3` + + .. attribute:: axis_a + + The first cuboid axis + + :type: :class:`CuboidAxis` + + .. attribute:: axis_b + + The second cuboid axis + + :type: :class:`CuboidAxis` + + .. attribute:: axis_c + + The third cuboid axis + + :type: :class:`CuboidAxis` + +Operations on Geometrical Objects +-------------------------------------------------------------------------------- + +.. function:: Angle(lhs, rhs) + + Calculate the angle (in radians) between `lhs` and `rhs`. + + :param lhs: First object + :type lhs: :class:`Line2`, :class:`Line3`, :class:`Plane` + + :param rhs: Second object + :type rhs: :class:`Line2`, :class:`Line3`, :class:`Plane` + + :rtype: float + +.. function:: IntersectionPoint(lhs, rhs) + + Calculates and returns the intersection point between `lhs` and `rhs` + + :param lhs: First object + :type lhs: :class:`Line2`, :class:`Line3`, :class:`Plane` + + :param rhs: Second object + :type rhs: :class:`Line2`, :class:`Line3`, :class:`Plane` + + :raises: :exc:`GeomException` when the two objects do not intersect + :rtype: :class:`Vec3` (:class:`Vec2` in case of :class:`Line2`) + +.. function:: IntersectionLine(plane2, plane2) + + Returns the intersection line between `plane1` and `plane2`. + + :param plane1: The first plane + :type plane1: :class:`Plane` + :param plane2: The second plane + :type plane2: :class:`Plane` + + :raises: :exc:GeomException if the two planes are parallel. + +.. function:: Distance(lhs, rhs) + + Returns the minimal distance between `lhs` and `rhs`. + + :param lhs: First object + :type lhs: :class:`Line2`, :class:`Line3`, :class:`Plane` + + :param rhs: Second object + :type rhs: :class:`Line2`, :class:`Line3`, :class:`Plane` + + :rtype: float + +.. function:: IsOnLine(line, point, epsilon=geom.EPSILON) + + Check whether `point` lies on `line` and returns true if point i no further + away than `epsilon`. + + :rtype: bool + +.. function:: IsInPlane(plane, object, epsilon=geom.EPSILON) + + Check whether `object` lies in `plane` and returns true if the difference is + no bigger than `epsilon`. + + :param plane: The plane + :type plane: :class:`Plane` + :param object: The object + :type object: :class:`Vec3` or :class:`Line3` + + :rtype: bool + +.. function:: AreParallel(lhs, rhs, epsilon=geom.EPSILON) + + Check whether `lhs` and `rhs` are parallel and returns true, if the difference + is below the given treshold `epsilon`. + + :param lhs: First object + :type lhs: :class:`Line2`, :class:`Line3`, :class:`Plane` + + :param rhs: Second object + :type rhs: :class:`Line2`, :class:`Line3`, :class:`Plane` + + :rtype: bool + +.. function:: AreIntersecting(line1, line2, epsilon=geom.EPSILON) + + Check whether `line1` and `line2` are intersecting and returns true, if they + intersect below the given threshold `epsilon`. + + :param lhs: First line + :type lhs: :class:`Line2`, :class:`Line3` + + :param rhs: Second line + :type rhs: :class:`Line2`, :class:`Line3` + + :rtype: bool + + + +.. function:: IsInSphere(sphere, point) + + Check whether the `sphere` contains `point`. + + :rtype: bool \ No newline at end of file diff --git a/modules/geom/doc/geom.rst b/modules/geom/doc/geom.rst index 27accb014bd6291c9c96b861ecc4e4fb232c48da..d0412a1340ae8ebf248e3193f381801f85d0b05b 100644 --- a/modules/geom/doc/geom.rst +++ b/modules/geom/doc/geom.rst @@ -1,15 +1,16 @@ -:mod:`geom` -- vectors, matrices and geometrical objects +:mod:`~ost.geom` -- vectors, matrices and geometrical objects ================================================================================ -.. module:: geom +.. module:: ost.geom :synopsis: Functions and classes for vectors, matrices and geometrical objects in 2, 3 and four dimensions -The geom modules contains functions and classes for vectors, matrices and other geometrical objects in 2, 3 and four dimensions. +The geom modules contains functions and classes for vectors, matrices and other +geometrical objects in 2, 3 and four dimensions. .. toctree:: vec - - \ No newline at end of file + mat + composite \ No newline at end of file diff --git a/modules/geom/doc/mat.rst b/modules/geom/doc/mat.rst new file mode 100644 index 0000000000000000000000000000000000000000..c8736733a7a18533cf18e6fcf40ddecf6b3a52c7 --- /dev/null +++ b/modules/geom/doc/mat.rst @@ -0,0 +1,167 @@ +Matrices +================================================================================ + +.. currentmodule:: ost.geom + +The :mod:`~ost.geom` module defines matrices in two, three and four dimensions. +All matrices store the values in row-major order, meaning that, the matrix ((1, +2), (3,4)) stores the values as (1, 2, 3, 4). This is illustrated in +the following code examples: + +.. code-block:: python + + m=geom.Mat2(1, 2, 3, 4) + print m # will print {{1,2},{3,4}} + print m[(0,0)], m[(0,1)], m[(1,0)], m[(1,1)] # will print 1, 2, 3, 4 + +Matrices support arithmetic via overloaded operators. The following operations are +supported: + + * adding and subtracting two matrices + * negation + * multiplication of matrices + * multiplying and dividing by scalar value + +The Matrix Classes +-------------------------------------------------------------------------------- + +.. class:: Mat2() + Mat2(d00, d01, d10, d11) + + 2x2 real-valued matrix. The first signature creates a new identity matrix. The + second signature initializes the matrix in row-major order. + + .. staticmethod:: Identity() + + Returns the 2x2 identity matrix + + +.. class:: Mat3() + Mat3(d00, d01, d02, d10, d11, d12, d20, d21, d22) + + 3x3 real-valued matrix. The first signature creates a new identity matrix. The + second signature initializes the matrix in row-major order. + + .. staticmethod:: Identity() + + Returns the 3x3 identity matrix + +.. class:: Mat4() + Mat4(d00, d01, d02, d03, d10, d11, d12, d13, d20, d21, d22, d23, d30, d31, d32, d33) + + 4x4 real-valued matrix. The first signature creates a new identity matrix. The + second signature initializes the matrix in row-major order. + + .. method:: ExtractRotation() + + Returns the 3x3 submatrix + + .. method:: PasteRotation(mat) + + Set the 3x3 submatrix of the top-left corner to `mat` + + .. method:: ExtractTranslation() + + Extract translation component from matrix. Only meaningful when matrix + is a combination of rotation and translation matrices, otherwise the result + is undefined. + + .. PasteTranslation(trans) + + Set the translation component of the matrix to `trans` + + :param trans: The translation + :type trans: :class:`Vec3` + + .. staticmethod:: Identity() + + Returns the 4x4 identity matrix + +Functions Operating on Matrices +-------------------------------------------------------------------------------- +.. function:: Equal(lhs, rhs, epsilon=geom.EPSILON) + + Compares the two matrices `lhs` and `rhs` and returns True, if all + of the element-wise differences are smaller than epsilon. `lhs` + and `rhs` must be matrices of the same dimension. + + :param lhs: First matrix + :type lhs: :class:`Mat2`, :class:`Mat3` or :class:`Mat4` + :param rhs: Second matrix + :type rhs: :class:`Mat2`, :class:`Mat3` or :class:`Mat4` + +.. function:: Transpose(mat) + + Returns the transpose of `mat` + + :param mat: The matrix to be transposed + :type lhs: :class:`Mat2`, :class:`Mat3` or :class:`Mat4` + +.. function:: Invert(mat) + + Returns the inverse of `mat` + + :param mat: The matrix to be inverted + :type mat: :class:`Mat2`, :class:`Mat3` or :class:`Mat4` + + What happens when determinant is 0? + +.. function:: CompMultiply(lhs, rhs) + + Returns the component-wise product of `lhs` and `rhs`. `lhs` and + `rhs` must be vectors of the same dimension. + + :param lhs: The lefthand-side vector + :type lhs: :class:`~Vec2`, :class:`~Vec3` or + :class:`~Vec4` + :param rhs: The righthand-side vector + :type rhs: :class:`~Vec2`, :class:`~Vec3` or + :class:`~Vec4` + +.. function:: CompDivide(lhs, rhs) + + Returns the component-wise quotient of `lhs` divided by `rhs`. `lhs` + and `rhs` must be vectors of the same dimension. + + :param lhs: The lefthand-side vector + :type lhs: :class:`~Vec2`, :class:`~Vec3` or + :class:`~Vec4` + :param rhs: The righthand-side vector + :type rhs: :class:`~Vec2`, :class:`~Vec3` or + :class:`~Vec4` + +.. function:: Det(mat) + + Returns the determinant of `mat` + :param mat: A matrix + :type mat: :class:`~Mat2`, :class:`~Mat3` or :class:`~Mat4` + +.. function:: Minor(mat, i, j) + + Returns the determinant of the 2x2 matrix generated from `mat` by + removing the ith row and jth column. + +.. function:: EulerTransformation(phi, theta, xi) + + Returns a rotation matrix for the 3 euler angles `phi`, `theta`, and + `xi`. The 3 angles are given in radians. + + +.. function:: AxisRotation(axis, angle) + + Returns a rotation matrix that represents a rotation of `angle` + around the `axis`. + + :param axis: The rotation axis. Will be normalized + :type axis: :class:`Vec3` + :param angle: Rotation angle (radians) in clockwise direction when + looking down the axis. + +.. function:: OrthogonalVector(vec) + + Get arbitrary vector orthogonal to `vec`. The returned vector is of length + 1, except when `vec` is a zero vector. In that case, the returned vector is + (0, 0, 0). + + :param vec: A vector of arbitrary length + :type vec: :class:`Vec3` \ No newline at end of file diff --git a/modules/geom/doc/vec.rst b/modules/geom/doc/vec.rst index b3da8088bc8748bdede06b340ecb3e0222db4555..d3876bcb1f9b46049869a3be84e51bdef9ff7e23 100644 --- a/modules/geom/doc/vec.rst +++ b/modules/geom/doc/vec.rst @@ -1,9 +1,11 @@ Vectors ================================================================================ -.. currentmodule:: geom +.. currentmodule:: ost.geom -The :class:`Vec2`, :class:`Vec3`, :class:`Vec4` classes implement vectors in 2, 3 and four dimensions. They support basic arithmetic via overloaded operators. Essentially, the following basic operations are available: +The :class:`Vec2`, :class:`Vec3`, :class:`Vec4` classes implement vectors in 2, +3 and four dimensions. They support basic arithmetic via overloaded operators. +Essentially, the following basic operations are available: * adding and subtracting two vectors * negation @@ -19,7 +21,8 @@ This is shown in the following example: print vec_a+vec_b print vec_a*3-vec_b -The standard vector operations are implemented as :ref:`free standing functions <vector-functions>`: +The standard vector operations are implemented as :ref:`free standing functions +<vector-functions>`: .. code-block:: python diff --git a/modules/geom/pymod/export_composite2.cc b/modules/geom/pymod/export_composite2.cc index f9e793ee10d7e05eddc608113e3d28c43146ec8e..96f42ab26ebfb5ed216aa285d2d3499ecb626bb7 100644 --- a/modules/geom/pymod/export_composite2.cc +++ b/modules/geom/pymod/export_composite2.cc @@ -42,6 +42,8 @@ void export_Composite2() .def("At",&Line2::At) .def("GetOrigin",&Line2::GetOrigin) .def("GetDirection",&Line2::GetDirection) + .add_property("direction", &Line2::GetDirection) + .add_property("origin", &Line2::GetOrigin) ; class_<Polygon2>("Polygon2",init<>()) diff --git a/modules/geom/pymod/export_composite3.cc b/modules/geom/pymod/export_composite3.cc index 8468578df28234c4b1d2ad11eafa6b57a4cde915..bf269d55258f21ba21a56c010654ae3a3ab9e47d 100644 --- a/modules/geom/pymod/export_composite3.cc +++ b/modules/geom/pymod/export_composite3.cc @@ -18,10 +18,9 @@ //------------------------------------------------------------------------------ #include <boost/python.hpp> #include <boost/python/suite/indexing/vector_indexing_suite.hpp> -using namespace boost::python; - #include <ost/geom/geom.hh> +using namespace boost::python; void export_Composite3() { using namespace geom; @@ -32,6 +31,8 @@ void export_Composite3() .def("At",&Line3::At) .def("GetOrigin",&Line3::GetOrigin) .def("GetDirection",&Line3::GetDirection) + .add_property("origin", &Line3::GetOrigin) + .add_property("direction", &Line3::GetDirection) ; { // scope @@ -49,6 +50,7 @@ scope PlaneScope = .def("GetNormal",&Plane::GetNormal) .add_property("normal", &Plane::GetNormal) .add_property("origin", &Plane::GetOrigin) + .add_property("p", &Plane::GetP) .def("GetP",&Plane::GetP) ; @@ -105,6 +107,8 @@ scope PlaneScope = .def(init<const Vec3&,Real>()) .def("GetOrigin",&Sphere::GetOrigin) .def("GetRadius",&Sphere::GetRadius) + .add_property("origin", &Sphere::GetOrigin, &Sphere::SetOrigin) + .add_property("radius", &Sphere::GetRadius, &Sphere::SetRadius) ; class_<CuboidAxis>("CuboidAxis", init<>()) @@ -113,29 +117,50 @@ scope PlaneScope = .def("GetVector", &CuboidAxis::GetVector, return_value_policy<copy_const_reference>()) .def("GetExtent", &CuboidAxis::GetExtent) + + .add_property("vector", make_function(&CuboidAxis::GetVector, + return_value_policy<copy_const_reference>())) + .add_property("half_extent", &CuboidAxis::GetHalfExtent) + .add_property("extent", &CuboidAxis::GetExtent) ; class_<Cuboid>("Cuboid", init<>()) .def(init<const geom::Vec3&, const CuboidAxis&,const CuboidAxis&, const CuboidAxis&>()) .def("GetCenter",&Cuboid::GetCenter) + .add_property("center", &Cuboid::GetCenter) .def("GetVecA", &Cuboid::GetVecA, return_value_policy<copy_const_reference>()) + .add_property("vec_a", make_function(&Cuboid::GetVecA, + return_value_policy<copy_const_reference>())) .def("GetVecB", &Cuboid::GetVecB, return_value_policy<copy_const_reference>()) + .add_property("vec_b", make_function(&Cuboid::GetVecB, + return_value_policy<copy_const_reference>())) .def("GetVecC", &Cuboid::GetVecC, return_value_policy<copy_const_reference>()) + .add_property("vec_c", make_function(&Cuboid::GetVecC, + return_value_policy<copy_const_reference>())) .def("GetAxisA", &Cuboid::GetAxisA, return_value_policy<copy_const_reference>()) + .add_property("axis_a", make_function(&Cuboid::GetAxisA, + return_value_policy<copy_const_reference>())) .def("GetAxisB", &Cuboid::GetAxisB, return_value_policy<copy_const_reference>()) + .add_property("axis_b", make_function(&Cuboid::GetAxisB, + return_value_policy<copy_const_reference>())) .def("GetAxisC", &Cuboid::GetAxisC, - return_value_policy<copy_const_reference>()) + return_value_policy<copy_const_reference>()) + .add_property("axis_c", make_function(&Cuboid::GetAxisC, + return_value_policy<copy_const_reference>())) .def("GetHalfExtents", &Cuboid::GetHalfExtents) + .add_property("half_extents", &Cuboid::GetHalfExtents) ; class_<AlignedCuboid>("AlignedCuboid", init<geom::Vec3, geom::Vec3>()) - .def("GetMin", &AlignedCuboid::GetMin, return_value_policy<copy_const_reference>()) - .def("GetMax", &AlignedCuboid::GetMax, return_value_policy<copy_const_reference>()) + .def("GetMin", &AlignedCuboid::GetMin, + return_value_policy<copy_const_reference>()) + .def("GetMax", &AlignedCuboid::GetMax, + return_value_policy<copy_const_reference>()) ; } diff --git a/modules/geom/pymod/export_vec2.cc b/modules/geom/pymod/export_vec2.cc index 6c0722ffcbb2117886fa96c6065bf52b2e292029..d32c72ad96b063fc432c7bb976277df966fd67e6 100644 --- a/modules/geom/pymod/export_vec2.cc +++ b/modules/geom/pymod/export_vec2.cc @@ -30,6 +30,7 @@ void export_Vec2() class_<Vec2>("Vec2",init<>()) .def(init<Real,Real>()) + .def(init<const Vec2&>()) .def(init<const Vec3&>()) .def(init<const Vec4&>()) .def(self *= Real()) diff --git a/modules/geom/pymod/export_vec3.cc b/modules/geom/pymod/export_vec3.cc index f822214b2ad4f2399abb387770f1e8d53a867f18..b9bf4edea774e85e83916826d2f6b77ace2b35d6 100644 --- a/modules/geom/pymod/export_vec3.cc +++ b/modules/geom/pymod/export_vec3.cc @@ -38,6 +38,7 @@ void export_Vec3() .def(init<Real,Real,Real>()) .def(init<const Vec2&>()) .def(init<const Vec4&>()) + .def(init<const Vec3&>()) .def(self *= Real()) .def(self /= Real()) .def(self += Real()) diff --git a/modules/geom/pymod/export_vec4.cc b/modules/geom/pymod/export_vec4.cc index 8a4f9e2f318964a7cdaa3fc0c9a2f1d8ce8da50e..9bb3936546528df0886681c88656a11b8b61c12c 100644 --- a/modules/geom/pymod/export_vec4.cc +++ b/modules/geom/pymod/export_vec4.cc @@ -35,6 +35,7 @@ void export_Vec4() .def(init<Real,Real,Real,Real>()) .def(init<const Vec2&>()) .def(init<const Vec3&>()) + .def(init<const Vec4&>()) .def(self *= Real()) .def(self /= Real()) .def(self += Real()) diff --git a/modules/geom/pymod/export_vecmat3_op.cc b/modules/geom/pymod/export_vecmat3_op.cc index 6500b4283fab6a7d7ed834f12d3f98abe2d3e737..cdafc821ce62797a555c1c2b98e29f661208e3ce 100644 --- a/modules/geom/pymod/export_vecmat3_op.cc +++ b/modules/geom/pymod/export_vecmat3_op.cc @@ -58,4 +58,5 @@ void export_VecMat3_op() def("Minor",Mat3Minor); def("EulerTransformation",EulerTransformation); def("AxisRotation",AxisRotation); + def("OrthogonalVector",OrthogonalVector); } diff --git a/modules/geom/src/vecmat3_op.hh b/modules/geom/src/vecmat3_op.hh index 43961e798eebaea9a6943e0d59ed4ceb5531b9f6..44c835768d3355e5c01e7785df971d9886162494 100644 --- a/modules/geom/src/vecmat3_op.hh +++ b/modules/geom/src/vecmat3_op.hh @@ -36,10 +36,12 @@ Real DLLEXPORT_OST_GEOM Length(const Vec3& v); Real DLLEXPORT_OST_GEOM Length2(const Vec3& v); //! return true if components differ not more than ephilon -bool DLLEXPORT_OST_GEOM Equal(const Vec3& v1, const Vec3& v2, Real ephilon=EPSILON); +bool DLLEXPORT_OST_GEOM Equal(const Vec3& v1, const Vec3& v2, + Real ephilon=EPSILON); //! return true if components differ not more than ephilon -bool DLLEXPORT_OST_GEOM Equal(const Mat3& m1, const Mat3& m2, Real ephilon=EPSILON); +bool DLLEXPORT_OST_GEOM Equal(const Mat3& m1, const Mat3& m2, + Real ephilon=EPSILON); //! vector dot product Real DLLEXPORT_OST_GEOM Dot(const Vec3& v1, const Vec3& v2); diff --git a/modules/gfx/pymod/export_entity.cc b/modules/gfx/pymod/export_entity.cc index 23e341b04754d0d960e78747277459dba023d54c..a81f8299ea0cdc549b1fb34b0255cdb66f4938d7 100644 --- a/modules/gfx/pymod/export_entity.cc +++ b/modules/gfx/pymod/export_entity.cc @@ -23,7 +23,7 @@ using namespace boost::python; #include <ost/gfx/entity.hh> using namespace ost; using namespace ost::gfx; - +#include <ost/export_helper/pair_to_tuple_conv.hh> #include "color_by_def.hh" namespace { @@ -177,14 +177,6 @@ void ent_apply_62(Entity* e, MapHandleColorOp& mhco){ } #endif //OST_IMG_ENABLED -template<class T1, class T2> -struct PairToTupleConverter { - static PyObject* convert(const std::pair<T1, T2>& pair) { - tuple t=boost::python::make_tuple<T1,T2>(pair.first,pair.second); - return incref(t.ptr()); - } -}; - RenderOptionsPtr ent_sline_opts(Entity* ent) { diff --git a/modules/gfx/pymod/export_map.cc b/modules/gfx/pymod/export_map.cc index cd88c771b87675032b12d8e730b00db5938230d1..7ba389b904f3ede92584241eb1890bce10833387 100644 --- a/modules/gfx/pymod/export_map.cc +++ b/modules/gfx/pymod/export_map.cc @@ -17,6 +17,7 @@ // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA //------------------------------------------------------------------------------ #include <boost/python.hpp> +#include <boost/python/suite/indexing/vector_indexing_suite.hpp> using namespace boost::python; #include <ost/gfx/map_iso.hh> @@ -50,13 +51,32 @@ void ms_color_by_04(MapSlab *s, const Color& c1, const Color& c2) void export_Map() { + + enum_<MapIsoType>("MapIsoType") + .value("ORIGINAL_MAP", ORIGINAL_MAP) + .value("DOWNSAMPLED_MAP", DOWNSAMPLED_MAP) + ; + class_<MapIso, bases<GfxObj>, boost::shared_ptr<MapIso>, boost::noncopyable>("MapIso", init<const String&, const ::img::MapHandle&, float, optional<uint> >()) .def("SetLevel",&MapIso::SetLevel) .def("GetLevel",&MapIso::GetLevel) + .def("GetMinLevel",&MapIso::GetMinLevel) + .def("GetMaxLevel",&MapIso::GetMaxLevel) .def("GetMean", &MapIso::GetMean) + .def("GetHistogram",&MapIso::GetHistogram) + .def("SetHistogramBinCount",&MapIso::SetHistogramBinCount) + .def("GetHistogramBinCount",&MapIso::GetHistogramBinCount) + .def("GetMap", &MapIso::GetMap,return_value_policy<reference_existing_object>()) .def("GetOriginalMap", &MapIso::GetOriginalMap,return_value_policy<reference_existing_object>()) + .def("GetDownsampledMap", &MapIso::GetDownsampledMap,return_value_policy<reference_existing_object>()) + .def("ShowDownsampledMap", &MapIso::ShowDownsampledMap) + .def("ShowOriginalMap", &MapIso::ShowOriginalMap) + .def("IsDownsampledMapAvailable", &MapIso::IsDownsampledMapAvailable) + .def("GetShownMapType", &MapIso::GetShownMapType) + .def("MakeOctreeDirty", &MapIso::MakeOctreeDirty) + .def("IfOctreeDirty", &MapIso::IfOctreeDirty) .def("Rebuild", &MapIso::Rebuild) .def("SetNSF",&MapIso::SetNSF) .def("SetColor", &MapIso::SetColor) diff --git a/modules/gfx/pymod/export_surface.cc b/modules/gfx/pymod/export_surface.cc index a2f8a560a275507fff3a5ba4cfe74838ddb1169e..4a4ebc88287f4ea3521a47f998ee9fbeb9b6b266 100644 --- a/modules/gfx/pymod/export_surface.cc +++ b/modules/gfx/pymod/export_surface.cc @@ -122,8 +122,4 @@ void export_Surface() .def("CleanColorOps", &Surface::CleanColorOps) .def("ReapplyColorOps", &Surface::ReapplyColorOps) ; - - class_<RSurface, bases<GfxObj>, RSurfaceP, boost::noncopyable>("RSurface", init<const String&, const mol::rsurf::RSurfP&>()) - ; - } diff --git a/modules/gfx/src/entity.cc b/modules/gfx/src/entity.cc index f7b924c135861728223d9532b21d015ff2cc0a33..8d639a33665cddc437adb568d27b1f8c56f89723 100644 --- a/modules/gfx/src/entity.cc +++ b/modules/gfx/src/entity.cc @@ -249,7 +249,7 @@ void Entity::ProcessLimits(geom::Vec3& minc, geom::Vec3& maxc, maxc = geom::Max(maxc, geom::Max(t1, geom::Max(t2, geom::Max(t3, geom::Max(t4, geom::Max(t5, geom::Max(t6, geom::Max(t7, t8)))))))); - } catch(Error& e) { + } catch(Error&) { // in case the object is empty... } } diff --git a/modules/gfx/src/gfx_object.cc b/modules/gfx/src/gfx_object.cc index 0a28a7e6e6dc30da9d3132f620e334b448b11add..c0d24ff0e1729f3dd5e7964248a9ada6f5f66a99 100644 --- a/modules/gfx/src/gfx_object.cc +++ b/modules/gfx/src/gfx_object.cc @@ -114,7 +114,7 @@ void GfxObj::ProcessLimits(geom::Vec3& minc, geom::Vec3& maxc, maxc = geom::Max(maxc, geom::Max(t1, geom::Max(t2, geom::Max(t3, geom::Max(t4, geom::Max(t5, geom::Max(t6, geom::Max(t7, t8)))))))); - } catch(Error& e) { + } catch(Error&) { // in case the object is empty... } } diff --git a/modules/gfx/src/impl/entity_detail.cc b/modules/gfx/src/impl/entity_detail.cc index ccc1600789034bef35990df5624102324dec4d60..572de5bb7e2b995fba33d204cf3e7745110a42f5 100644 --- a/modules/gfx/src/impl/entity_detail.cc +++ b/modules/gfx/src/impl/entity_detail.cc @@ -43,9 +43,9 @@ void GfxView::AddAtom(const AtomView& av) AtomEntry ae(a,default_radius, a.GetRadius(), GfxObj::Ele2Color(a.GetElement())); - atom_map[a.GetHashCode()]=ae; + atom_map[a.GetHandle().GetHashCode()]=ae; if(av.GetBondCount()==0) { - orphan_atom_list.push_back(a.GetHashCode()); + orphan_atom_list.push_back(a.GetHandle().GetHashCode()); } } @@ -297,7 +297,7 @@ SplineEntryList Spline::Generate(int nsub) const float psum=0.0; float qsum=0.0; ++c; - while(sublist[c].type==1 && c<nsub*size) { + while(c<nsub*size && sublist[c].type==1) { n = geom::Normalize(geom::Cross(sublist[c].normal, sublist[c].direction)); geom::Vec3 p1 = sublist[c].position+n; diff --git a/modules/gfx/src/impl/map_octree.cc b/modules/gfx/src/impl/map_octree.cc index 33bd93d71ae00f0601015b6ba0571b96621e7a62..a130b6552b3bb032a2239e0b1de9f8033dcc5f2c 100644 --- a/modules/gfx/src/impl/map_octree.cc +++ b/modules/gfx/src/impl/map_octree.cc @@ -25,12 +25,34 @@ namespace ost { namespace gfx { namespace impl { -MapOctree::MapOctree(const img::ImageHandle& map): - map_(map) +MapOctree::MapOctree(const img::ImageHandle& ih): + map_(ih), + built_(false) +{} + +void MapOctree::Initialize() { + built_=false; + levels_.clear(); this->BuildOctree(); } + +void MapOctree::SetNewMap(const img::ImageHandle& ih) +{ + map_=ih; +} + +bool MapOctree::IsMapManageable (const img::ImageHandle ih) +{ + bool manageable = true; + if (ih.GetExtent().GetWidth() > 256 || + ih.GetExtent().GetHeight() > 256 || + ih.GetExtent().GetDepth() > 256 ) manageable=false; + return manageable; +} + + uint32_t MapOctree::GetNumNodesForLevel(uint8_t level) const { img::Size size=map_.GetExtent().GetSize(); @@ -52,7 +74,9 @@ void MapOctree::BuildOctree() assert(p && "Octree only supports real spatial images"); OctreeNode dummy; this->BuildOctreeRec(range_vec, 0, p, map_.GetExtent(), dummy); + built_=true; } + std::pair<float,float> MapOctree::BuildOctreeRec(const OcRangeVector& range_vec, uint16_t level, img::RealSpatialImageState* map, @@ -100,9 +124,9 @@ std::pair<float,float> MapOctree::BuildOctreeRec(const OcRangeVector& range_vec, } // determine branch pattern uint16_t highest_order_mask=1 << highest_order_bit; - bool branch_x=range_vec.x & highest_order_mask; - bool branch_y=range_vec.y & highest_order_mask; - bool branch_z=range_vec.z & highest_order_mask; + bool branch_x=(range_vec.x & highest_order_mask)!= 0; + bool branch_y=(range_vec.y & highest_order_mask)!= 0; + bool branch_z=(range_vec.z & highest_order_mask)!= 0; int range_x[2][2]; int range_y[2][2]; int range_z[2][2]; diff --git a/modules/gfx/src/impl/map_octree.hh b/modules/gfx/src/impl/map_octree.hh index 999219e83880049f6df6e0f4c0cde3d9558fd778..4c73f54bd0664d29b0b9c76a63172675fbfa4263 100644 --- a/modules/gfx/src/impl/map_octree.hh +++ b/modules/gfx/src/impl/map_octree.hh @@ -109,8 +109,11 @@ typedef std::vector<OctreeNode> OcNodeEntryList; class DLLEXPORT_OST_GFX MapOctree { public: MapOctree(const img::ImageHandle& map); + void Initialize(); uint32_t GetNumNodesForLevel(uint8_t level) const; - + void SetNewMap(const img::ImageHandle& ih); + static bool IsMapManageable (const img::ImageHandle ih); + /// \brief depth-first visit of octree nodes template <typename F> void VisitDF(F& f) const @@ -216,6 +219,7 @@ private: img::ImageHandle map_; std::vector<OcNodeEntryList> levels_; + bool built_; }; }}} diff --git a/modules/gfx/src/map_iso.cc b/modules/gfx/src/map_iso.cc index 20736f6c981ebafc4426a17ff2253355259e3275..06183729ac58cbdbb5fd054858addd2795314a0f 100644 --- a/modules/gfx/src/map_iso.cc +++ b/modules/gfx/src/map_iso.cc @@ -24,8 +24,8 @@ #include <ost/profile.hh> #include <ost/profile.hh> #include <ost/base.hh> -#include <ost/img/alg/stat.hh> #include <ost/img/alg/discrete_shrink.hh> +#include <ost/img/alg/histogram.hh> #include "gl_helper.hh" #include "glext_include.hh" @@ -62,9 +62,12 @@ namespace gfx { MapIso::MapIso(const String& name, const img::MapHandle& mh, float level): GfxObj(name), original_mh_(mh), - downsampled_mh_(MapIso::DownsampleMap(mh)), - mh_(downsampled_mh_), + downsampled_mh_(), + mh_(MapIso::DownsampleMap(mh)), octree_(mh_), + stat_calculated_(false), + histogram_calculated_(false), + histogram_bin_count_(100), level_(level), normals_calculated_(false), alg_(0), @@ -72,6 +75,11 @@ MapIso::MapIso(const String& name, const img::MapHandle& mh, float level): debug_octree_(false), color_(Color::GREY) { + // TODO replace with def mat for this gfx obj type + if (mh_ != original_mh_) { + downsampled_mh_ = mh_; + } + octree_.Initialize(); SetMatAmb(Color(0,0,0)); SetMatDiff(Color(1,1,1)); SetMatSpec(Color(0.1,0.1,0.1)); @@ -87,16 +95,23 @@ MapIso::MapIso(const String& name, const img::MapHandle& mh, float level, uint a): GfxObj(name), original_mh_(mh), - downsampled_mh_(MapIso::DownsampleMap(mh)), - mh_(downsampled_mh_), + downsampled_mh_(), + mh_(MapIso::DownsampleMap(mh)), octree_(mh_), + stat_calculated_(false), + histogram_calculated_(false), + histogram_bin_count_(100), level_(level), normals_calculated_(false), alg_(a), debug_octree_(false), - color_(Color::GREY) + color_(Color::GREY) { // TODO replace with def mat for this gfx obj type + if (mh_ != original_mh_) { + downsampled_mh_ = mh_; + } + octree_.Initialize(); SetMatAmb(Color(0,0,0)); SetMatDiff(Color(1,1,1)); SetMatSpec(Color(0.1,0.1,0.1)); @@ -261,6 +276,16 @@ void MapIso::OnInput(const InputEvent& e) void MapIso::Rebuild() { + if (mh_.IsFrequency() == true){ + throw Error("Error: Map not in real space. Cannot create of this map"); + } + if (octree_.IsMapManageable(mh_) == false) { + throw Error("Error: Map is too big for visualization"); + } + if (IfOctreeDirty()==true) { + octree_.SetNewMap(mh_); + octree_.Initialize(); + } va_.Clear(); va_.SetMode(0x2); normals_calculated_=false; @@ -273,7 +298,7 @@ void MapIso::Rebuild() va_.CalcNormals(1.0); va_.DrawNormals(true); #endif - OnRenderModeChange(); + OnRenderModeChange(); } void MapIso::SetLevel(float l) @@ -283,6 +308,31 @@ void MapIso::SetLevel(float l) Scene::Instance().RequestRedraw(); } +void MapIso::CalculateStat() const +{ + mh_.ApplyIP(stat_); + stat_calculated_=true; +} + +void MapIso::CalculateHistogram() const +{ + histogram_ = img::alg::HistogramBase(histogram_bin_count_, this->GetMinLevel(), this->GetMaxLevel()); + mh_.ApplyIP(histogram_); + histogram_calculated_=true; +} + +float MapIso::GetMinLevel() const +{ + if(!stat_calculated_)CalculateStat(); + return stat_.GetMinimum(); +} + +float MapIso::GetMaxLevel() const +{ + if(!stat_calculated_)CalculateStat(); + return stat_.GetMaximum(); +} + float MapIso::GetLevel() const { return level_; @@ -290,9 +340,27 @@ float MapIso::GetLevel() const float MapIso::GetStdDev() const { - img::alg::Stat stat; - mh_.Apply(stat); - return stat.GetStandardDeviation(); + if(!stat_calculated_)CalculateStat(); + return stat_.GetStandardDeviation(); +} + +void MapIso::SetHistogramBinCount(int count) +{ + if (count > 0){ + histogram_bin_count_ = count; + histogram_calculated_ = false; + } +} + +int MapIso::GetHistogramBinCount() const +{ + return histogram_bin_count_; +} + +std::vector<int> MapIso::GetHistogram() const +{ + if(!histogram_calculated_)CalculateHistogram(); + return histogram_.GetBins(); } img::ImageHandle& MapIso::GetMap() @@ -305,11 +373,15 @@ img::ImageHandle& MapIso::GetOriginalMap() return original_mh_; } +img::ImageHandle& MapIso::GetDownsampledMap() +{ + return downsampled_mh_; +} + float MapIso::GetMean() const { - img::alg::Stat stat; - mh_.Apply(stat); - return static_cast<float>(stat.GetMean()); + if(!stat_calculated_)CalculateStat(); + return static_cast<float>(stat_.GetMean()); } void MapIso::SetNSF(float nsf) @@ -319,11 +391,60 @@ void MapIso::SetNSF(float nsf) Scene::Instance().RequestRedraw(); } +/// \brief sets the donsampled map to active +void MapIso::ShowDownsampledMap() +{ + if (downsampled_mh_.IsValid()) mh_ = downsampled_mh_; + MakeOctreeDirty(); + stat_calculated_ = false; + histogram_calculated_ = false; + Rebuild(); + Scene::Instance().RequestRedraw(); +} + +/// \brief sets the original map to active +void MapIso::ShowOriginalMap() +{ + if (original_mh_.IsValid()) mh_ = original_mh_; + MakeOctreeDirty(); + stat_calculated_ = false; + histogram_calculated_ = false; + Rebuild(); + Scene::Instance().RequestRedraw(); +} + + +void MapIso::MakeOctreeDirty() +{ + dirty_octree_=true; +} + +MapIsoType MapIso::GetShownMapType() const +{ + MapIsoType ret = ORIGINAL_MAP; + if (mh_ == downsampled_mh_) { + ret = DOWNSAMPLED_MAP; + } + return ret; +} + +bool MapIso::IfOctreeDirty() const +{ + return dirty_octree_; +} + +/// \brief checks if the downsampled map is available +bool MapIso::IsDownsampledMapAvailable() const +{ + return !(downsampled_mh_==img::ImageHandle()); +} + img::ImageHandle MapIso::DownsampleMap(const img::ImageHandle& mh) { uint downsampling_fact = compute_downsampling_fact(mh); img:: ImageHandle ret_mh = mh; if (downsampling_fact != 1) { + LOG_MESSAGE("Downsampling map for more comfortable visualization") img::alg::DiscreteShrink shrink_alg(img::Size(downsampling_fact,downsampling_fact,downsampling_fact)); ret_mh = mh.Apply(shrink_alg); } diff --git a/modules/gfx/src/map_iso.hh b/modules/gfx/src/map_iso.hh index 87eda29a9c988b8d0a0a2623487d5f7476210269..9ed928632c301b6d500b604babc085f24ce72e08 100644 --- a/modules/gfx/src/map_iso.hh +++ b/modules/gfx/src/map_iso.hh @@ -26,12 +26,20 @@ #include <boost/shared_ptr.hpp> #include <ost/img/map.hh> +#include <ost/img/alg/stat.hh> +#include <ost/img/alg/histogram.hh> + #include <ost/gfx/impl/map_octree.hh> #include "gfx_object.hh" #include "map_iso_prop.hh" namespace ost { namespace gfx { +enum MapIsoType { + ORIGINAL_MAP, + DOWNSAMPLED_MAP +}; + class MapIso; typedef boost::shared_ptr<MapIso> MapIsoP; @@ -67,6 +75,9 @@ public: /// Will force rebuild of the vertex buffers/indices void SetLevel(float l); + float GetMinLevel() const; + float GetMaxLevel() const; + /// \brief get current isocontouring level float GetLevel() const; @@ -76,6 +87,16 @@ public: /// \brief get std dev of map. float GetStdDev() const; + + /// \brief get histogram + std::vector<int> GetHistogram() const; + + /// \brief set Histogram bin count + void SetHistogramBinCount(int count); + + /// \brief get Histogram bin count + int GetHistogramBinCount() const; + /// \brief get the map handle of the currently displayed map // The following is a hack. For the DataViewer I need to pass a reference to an ImagHandle // that never goes out of scope, so I get a reference from here @@ -86,6 +107,23 @@ public: // that never goes out of scope, so I get a reference from here img::ImageHandle& GetOriginalMap(); + /// \brief get the map handle of the downsampled map + // The following is a hack. For the DataViewer I need to pass a reference to an ImagHandle + // that never goes out of scope, so I get a reference from here + img::ImageHandle& GetDownsampledMap(); + + /// \brief sets the donwsampled map to active + void ShowDownsampledMap(); + + /// \brief sets the original map to active + void ShowOriginalMap(); + + /// \brief checks if the downsampled map is available + bool IsDownsampledMapAvailable() const ; + + /// \brief returns the type of map currently being show + MapIsoType GetShownMapType() const; + /// \brief set color /// /// By default, the color is white. @@ -100,25 +138,40 @@ public: const Color& GetColor() const { return color_; } void SetNSF(float smoothf); void SetDebugOctree(bool flag) { debug_octree_=flag; } + + /// \brief flags the octree to be rebuilt + void MakeOctreeDirty(); + + /// \brief checks is the octree needs to be rebuilt + bool IfOctreeDirty() const; + protected: + void CalculateStat() const; + void CalculateHistogram() const; virtual void CustomPreRenderGL(bool flag); static img::ImageHandle DownsampleMap(const img::ImageHandle& mh); private: - img::MapHandle original_mh_; - img::MapHandle downsampled_mh_; - img::MapHandle mh_; - impl::MapOctree octree_; - float level_; - bool normals_calculated_; - uint alg_; - float smoothf_; - float min_; - float max_; - float std_dev_; - float min_max_; - bool debug_octree_; - Color color_; + img::MapHandle original_mh_; + img::MapHandle downsampled_mh_; + img::MapHandle mh_; + impl::MapOctree octree_; + mutable img::alg::Stat stat_; + mutable bool stat_calculated_; + mutable img::alg::Histogram histogram_; + mutable bool histogram_calculated_; + int histogram_bin_count_; + float level_; + bool normals_calculated_; + uint alg_; + float smoothf_; + float min_; + float max_; + float std_dev_; + float min_max_; + bool debug_octree_; + Color color_; + bool dirty_octree_; }; }} diff --git a/modules/gfx/src/scene.cc b/modules/gfx/src/scene.cc index c85abc13d5e38dfb1ed38f3537ab66df7b37db6e..46af476261dc78f9552f4ec9f166669ec2fdbb7c 100644 --- a/modules/gfx/src/scene.cc +++ b/modules/gfx/src/scene.cc @@ -604,6 +604,7 @@ void Scene::Remove(const GfxNodeP& go) if(!go) return; root_node_->Remove(go); this->NotifyObservers(bind(&SceneObserver::NodeRemoved, _1,go)); + this->RequestRedraw(); } void Scene::Remove(const String& name) @@ -614,6 +615,7 @@ void Scene::Remove(const String& name) root_node_->Remove(name); if(GfxObjP go = dyn_cast<GfxObj>(fn.node)) { this->NotifyObservers(bind(&SceneObserver::NodeRemoved, _1,go)); + this->RequestRedraw(); } } } diff --git a/modules/gfx/src/surface.cc b/modules/gfx/src/surface.cc index e0d08cdc162ff04985d9dbeec79f0f725e20e922..dbf740077238e34c36356fe58e35cdeb473d8b51 100644 --- a/modules/gfx/src/surface.cc +++ b/modules/gfx/src/surface.cc @@ -360,169 +360,4 @@ void Surface::ReapplyColorOps(){ GfxObj::ReapplyColorOps(); } -// rsurf stuff -using namespace mol::rsurf; - -RSurface::RSurface(const String& name, const RSurfP& rs): - GfxObj(name), - rs_(rs) -{ - ArcList alist = rs->GetArcList(); - TetList tlist = rs->GetTetList(); - SphereList slist = rs->GetSphereList(); - - -#if 0 - for(TetList::const_iterator it=tlist.begin();it!=tlist.end();++it) { - VertexID id1 = va_.Add((*it)->A->pos,Vec3(),Color(1,1,1)); - VertexID id2 = va_.Add((*it)->B->pos,Vec3(),Color(1,1,1)); - VertexID id3 = va_.Add((*it)->C->pos,Vec3(),Color(1,1,1)); - VertexID id4 = va_.Add((*it)->cA,Vec3(),Color(0,1,0)); - VertexID id5 = va_.Add((*it)->cB,Vec3(),Color(0,1,0)); - VertexID id6 = va_.Add((*it)->cC,Vec3(),Color(0,1,0)); - va_.AddLine(id1,id4); - va_.AddLine(id2,id5); - va_.AddLine(id3,id6); - va_.AddLine(id4,id5); - va_.AddLine(id5,id6); - va_.AddLine(id6,id4); - } -#endif - -#if 0 - for(ArcList::const_iterator it=alist.begin();it!=alist.end();++it) { - Arc& arc= *(*it); - if(arc.S && arc.T) { - VertexID id0 = va_.Add(arc.S->pos,Vec3(),Color(1,0,0)); - VertexID id1 = va_.Add(arc.mid,Vec3(),Color(1,1,1)); - VertexID id2 = va_.Add(arc.T->pos,Vec3(),Color(1,0,1)); - VertexID id3 = va_.Add(arc.H->pos,Vec3(),Color(1,1,1)); - VertexID id4 = va_.Add(arc.K->pos,Vec3(),Color(1,1,1)); - va_.AddLine(id0,id1); - va_.AddLine(id1,id2); - va_.AddLine(id1,id3); - va_.AddLine(id1,id4); - } - } -#endif - - - for(SphereList::const_iterator it=slist.begin();it!=slist.end();++it) { - for(uint l=0;l<(*it)->arc_list_list.size();++l) { - const Sphere& sp = *(*it); - const ArcDirDeque& alist=sp.arc_list_list[l]; - if(alist.empty()) continue; - - if(alist.size()<4) continue; - Vec3 a0 = alist[0].inv_arc ? -alist[0].arc->axis : alist[0].arc->axis; - Vec3 a1 = alist[1].inv_arc ? -alist[1].arc->axis : alist[1].arc->axis; - Vec3 s0 = alist[0].inv_arc ? alist[0].arc->T->pos : alist[0].arc->S->pos; - Vec3 s1 = alist[1].inv_arc ? alist[1].arc->T->pos : alist[1].arc->S->pos; - Vec3 p0 = sp.pos+sp.rad*(s0-sp.pos)/((sp.rad+alist[0].arc->S->rad)); - Vec3 p1 = sp.pos+sp.rad*(s1-sp.pos)/((sp.rad+alist[1].arc->S->rad)); - - VertexID id00 = va_.Add(p0,Vec3(),Color(1,1,1)); - VertexID id10 = va_.Add(p1,Vec3(),Color(1,1,1)); - VertexID id20 = id00; - - for(float c=0.0;c<=1.0;c+=0.1) { - Mat3 r0 = AxisRotation(a0,c*alist[0].arc->phi); - Mat3 r1 = AxisRotation(a1,c*alist[1].arc->phi); - Vec3 v0 = r0*(p0-alist[0].arc->fixpoint)+alist[0].arc->fixpoint; - Vec3 v1 = r1*(p1-alist[1].arc->fixpoint)+alist[1].arc->fixpoint; - Vec3 v2 = r1*(v0-alist[1].arc->fixpoint)+alist[1].arc->fixpoint; - VertexID id01 = va_.Add(v0,Vec3(),Color(1,1,1)); - VertexID id11 = va_.Add(v1,Vec3(),Color(1,1,1)); - VertexID id21 = va_.Add(v2,Vec3(),Color(1,c,0)); - va_.AddLine(id00,id01); - va_.AddLine(id10,id11); - va_.AddLine(id20,id21); - id00=id01; - id10=id11; - id20=id21; - } - -#if 0 - Vec3 sum1; - Vec3 sum2; - Vec3 sum3; - Vec3 prev; - float plan=0.0; - for(uint i=0;i<alist.size();++i) { - uint j = (i-1+alist.size())%alist.size(); - uint k = (i+1)%alist.size(); - sum1+=(alist[i].arc->mid-sp.pos)*alist[i].arc->phi; - Vec3 d0 = alist[i].arc->S->pos-sp.pos; - Vec3 d1 = alist[i].arc->mid-sp.pos; - Vec3 d2 = alist[i].arc->T->pos-sp.pos; - - Vec3 p0 = sp.pos+sp.rad*(d0)/(sp.rad+alist[i].arc->S->rad); - Vec3 p1 = sp.pos+sp.rad*(d1)/(sp.rad+alist[i].arc->S->rad); - Vec3 p2 = sp.pos+sp.rad*(d2)/(sp.rad+alist[i].arc->S->rad); - Vec3 c0 = Normalize(Cross(Normalize(alist[i].w.pos-alist[i].v.pos), - Normalize(alist[k].w.pos-alist[k].v.pos))+ - Cross(Normalize(alist[j].w.pos-alist[j].v.pos), - Normalize(alist[i].w.pos-alist[i].v.pos))); - Vec3 c1 = Normalize(Cross(Normalize(p0-p1),Normalize(p2-p1))); - - if(i>0) { - plan+=Dot(prev,Normalize(d1)); - } - prev=Normalize(d1); - sum2+=c0*alist[i].arc->phi; - - VertexID id0 = va_.Add(p0,Vec3(),Color(1,1,0)); - VertexID id1 = va_.Add(p1,Vec3(),Color(1,1,1)); - VertexID id2 = va_.Add(p2,Vec3(),Color(1,1,0)); - VertexID id3 = va_.Add(sp.pos,Vec3(),Color(1,1,1)); - va_.AddLine(id0,id1); - va_.AddLine(id1,id2); - //va_.AddLine(id1,id3); - } - float f = plan/static_cast<float>(alist.size()); - VertexID id8 = va_.Add(sp.pos,Vec3(),Color(1,1,1)); - VertexID id9 = va_.Add(sp.pos+1.1*sp.rad*Normalize(sum1),Vec3(),Color(0,0,1)); - VertexID idA = va_.Add(sp.pos+1.1*sp.rad*Normalize(sum2),Vec3(),Color(1,0,0)); - VertexID idB = va_.Add(sp.pos+1.1*sp.rad*Normalize(f*sum1+(1.0-f)*sum2),Vec3(),Color(0,1,0)); - va_.AddLine(id8,id9); - va_.AddLine(id8,idA); - va_.AddLine(id8,idB); -#endif -#if 0 - VertexID id0 = va_.Add(sp.pos,Vec3(),Color(1,1,1)); - VertexID id1 = va_.Add(sp.top_list[l],Vec3(),Color(1,1,0)); - va_.AddLine(id0,id1); -#endif - } - } - - va_.SetMode(0x2); - va_.SetLighting(false); - va_.SetCullFace(false); - va_.SetColorMaterial(true); - -} - -Vec3 RSurface::GetCenter() const -{ - return Vec3(0,0,0); -} - -void RSurface::CustomRenderGL(RenderPass pass) -{ - if (!(pass==STANDARD_RENDER_PASS || pass==OPAQUE_RENDER_PASS)) - return; - va_.RenderGL(); -} - -geom::AlignedCuboid RSurface::GetBoundingBox() const -{ - return geom::AlignedCuboid(Vec3(-1,-1,-1), Vec3(1,1,1)); -} - -void RSurface::ProcessLimits(Vec3& minc, Vec3& maxc, const mol::Transform& tf) const -{ - // nop -} - }} // ns diff --git a/modules/gfx/src/surface.hh b/modules/gfx/src/surface.hh index 186d41dc29ba16e48dbc1dc506a62c23da16d285..c8fc12834e0fa5973116c8207dd9b74097bf5b52 100644 --- a/modules/gfx/src/surface.hh +++ b/modules/gfx/src/surface.hh @@ -123,24 +123,6 @@ private: boost::ptr_vector<gfx::ColorOp> c_ops_; }; -// temporary debug -class RSurface; -typedef boost::shared_ptr<RSurface> RSurfaceP; - -class DLLEXPORT_OST_GFX RSurface: public GfxObj { -public: - RSurface(const String& name, const mol::rsurf::RSurfP& rs); - virtual geom::Vec3 GetCenter() const; - virtual void CustomRenderGL(RenderPass pass); - - virtual geom::AlignedCuboid GetBoundingBox() const; - - virtual void ProcessLimits(geom::Vec3& minc, geom::Vec3& maxc, const mol::Transform& tf) const; - -private: - mol::rsurf::RSurfP rs_; -}; - }} // ns #endif diff --git a/modules/gfx/tests/CMakeLists.txt b/modules/gfx/tests/CMakeLists.txt index a055e099ec3cae573fbd508a1b7c453b4a25b056..fe6a3d670aac004534f5c650421273d47930cc3b 100644 --- a/modules/gfx/tests/CMakeLists.txt +++ b/modules/gfx/tests/CMakeLists.txt @@ -4,10 +4,8 @@ set(OST_GFX_UNIT_TESTS ) if (ENABLE_IMG) list(APPEND OST_GFX_UNIT_TESTS test_map_octree.cc) - - ost_unittest(gfx "${OST_GFX_UNIT_TESTS}") - - target_link_libraries(gfx_tests ost_io) endif() +ost_unittest(gfx "${OST_GFX_UNIT_TESTS}") +target_link_libraries(gfx_tests ost_io) diff --git a/modules/gfx/tests/test_ent_pov_export.cc b/modules/gfx/tests/test_ent_pov_export.cc index 450051dc73c9ffade08fa78b50e8cafdf111a13e..2d1717eac40d3349fb3e41307137e4c87de12250 100644 --- a/modules/gfx/tests/test_ent_pov_export.cc +++ b/modules/gfx/tests/test_ent_pov_export.cc @@ -22,12 +22,17 @@ */ #include <fstream> -#include <boost/test/unit_test.hpp> #include <ost/io/load_entity.hh> #include <ost/gfx/scene.hh> #include <ost/gfx/entity.hh> +#include <ost/test_utils/compare_files.hh> + +#define BOOST_TEST_DYN_LINK +#include <boost/test/unit_test.hpp> + using boost::unit_test_framework::test_suite; + using namespace ost; using namespace ost::gfx; @@ -42,36 +47,6 @@ boost::shared_ptr<Entity> prepare_object(gfx::RenderMode::Type mode) return gfx_ent; } -bool compare_files(const String& test, const String& gold_standard) -{ - std::ifstream test_stream(test.c_str()); - std::ifstream gold_stream(gold_standard.c_str()); - String test_line, gold_line; - while (true) { - bool test_end=std::getline(test_stream, test_line); - bool gold_end=std::getline(gold_stream, gold_line); - if (!(test_end || gold_end)) { - return true; - } - if (!test_end) { - std::cerr << gold_standard << " contains additional line(s):" - << std::endl << gold_line; - return false; - } - if (!gold_end) { - std::cerr << test << " contains additional line(s):" - << std::endl << test_line; - return false; - } - if (gold_line!=test_line) { - std::cerr << "line mismatch:" << std::endl << "test: " << test_line - << std::endl << "gold: " << gold_line; - return false; - } - } - return true; -} - // The GfxView uses a std::map for efficient access to atoms. This however has // implications for the POV export. In general we can't assume that the atoms // are written in any particular order. That's why we first filter out all @@ -129,6 +104,7 @@ bool compare_sphere_cyl_entries(const String& test, } } + BOOST_AUTO_TEST_SUITE(gfx) BOOST_AUTO_TEST_CASE(pov_export_simple) @@ -156,7 +132,7 @@ BOOST_AUTO_TEST_CASE(pov_export_cartoon) Scene::Instance().SetOffscreenMode(); boost::shared_ptr<Entity> obj=prepare_object(RenderMode::HSC); Scene::Instance().ExportPov("pov_cartoon_test", "."); - BOOST_CHECK(compare_files("pov_cartoon_test.inc", + BOOST_CHECK(ost::compare_files("pov_cartoon_test.inc", "testfiles/pov_cartoon_std.inc")); Scene::Instance().Remove(obj); } @@ -176,7 +152,7 @@ BOOST_AUTO_TEST_CASE(pov_export_trace) Scene::Instance().SetOffscreenMode(); boost::shared_ptr<Entity> obj=prepare_object(RenderMode::TRACE); Scene::Instance().ExportPov("pov_trace_test", "."); - BOOST_CHECK(compare_files("pov_trace_test.inc", + BOOST_CHECK(ost::compare_files("pov_trace_test.inc", "testfiles/pov_trace_std.inc")); Scene::Instance().Remove(obj); } @@ -186,7 +162,7 @@ BOOST_AUTO_TEST_CASE(pov_export_line_trace) Scene::Instance().SetOffscreenMode(); boost::shared_ptr<Entity> obj=prepare_object(RenderMode::LINE_TRACE); Scene::Instance().ExportPov("pov_line_trace_test", "."); - BOOST_CHECK(compare_files("pov_line_trace_test.inc", + BOOST_CHECK(ost::compare_files("pov_line_trace_test.inc", "testfiles/pov_line_trace_std.inc")); Scene::Instance().Remove(obj); } @@ -196,7 +172,7 @@ BOOST_AUTO_TEST_CASE(pov_export_sline) Scene::Instance().SetOffscreenMode(); boost::shared_ptr<Entity> obj=prepare_object(RenderMode::SLINE); Scene::Instance().ExportPov("pov_sline_test", "."); - BOOST_CHECK(compare_files("pov_sline_test.inc", + BOOST_CHECK(ost::compare_files("pov_sline_test.inc", "testfiles/pov_sline_std.inc")); Scene::Instance().Remove(obj); } diff --git a/modules/gfx/tests/test_map_octree.cc b/modules/gfx/tests/test_map_octree.cc index 819b38618d0b2293038e70289ee0b273999db26b..31dd637f712654e2da388212d95d2b266f3495c1 100644 --- a/modules/gfx/tests/test_map_octree.cc +++ b/modules/gfx/tests/test_map_octree.cc @@ -21,10 +21,14 @@ Author: Marco Biasini */ -#include <boost/test/unit_test.hpp> +#include <ost/gfx/impl/map_octree.hh> + #include <ost/img/image_handle.hh> #include <ost/img/image_factory.hh> -#include <ost/gfx/impl/map_octree.hh> + +#define BOOST_TEST_DYN_LINK +#include <boost/test/unit_test.hpp> + using boost::unit_test_framework::test_suite; using namespace ost; @@ -174,6 +178,7 @@ BOOST_AUTO_TEST_CASE(octree_power_of_two) img.SetReal(img::Point(0, 0, 1), 0.5f); Pow2Vis v; MapOctree octree(img); + octree.Initialize(); octree.VisitDF(v); BOOST_CHECK_EQUAL(v.leaf_count, 8); BOOST_CHECK_EQUAL(v.node_count, 1); @@ -192,6 +197,7 @@ BOOST_AUTO_TEST_CASE(octree_non_power_of_two) img.SetReal(img::Point(0, 0, 1), 0.5f); NonPow2Vis v; MapOctree octree(img); + octree.Initialize(); octree.VisitDF(v); } diff --git a/modules/gui/pymod/CMakeLists.txt b/modules/gui/pymod/CMakeLists.txt index 200515b96aa0b9986eb890f68f03f957b6a1196e..9b1353330c31cd0ca23136381ae83aba2ac43001 100644 --- a/modules/gui/pymod/CMakeLists.txt +++ b/modules/gui/pymod/CMakeLists.txt @@ -9,7 +9,6 @@ set(OST_GUI_PYMOD_SOURCES export_remote_site_loader.cc export_scene_win.cc export_sequence_viewer.cc - export_sequence_viewerV2.cc export_perspective.cc export_sip_handler.cc export_scene_selection.cc @@ -35,6 +34,7 @@ immutable_gradient_info_handler.py immutable_preset_info_handler.py init_inspector.py inspector_widget.py +map_level_widget.py preset.py preset_editor_list_model.py preset_editor_widget.py @@ -45,6 +45,7 @@ render_mode_widget.py render_op.py render_options_widget.py scene_observer_impl.py +scene_selection_helper.py simple_widget.py sline_widget.py toolbar_options_widget.py @@ -58,6 +59,7 @@ loader_list_model.py loader_manager_widget.py immutable_loader_info_handler.py line_trace_widget.py +wireframe_widget.py ) if (ENABLE_IMG) list(APPEND OST_GUI_PYMOD_SOURCES diff --git a/modules/gui/pymod/export_gosty.cc b/modules/gui/pymod/export_gosty.cc index 9cd97b7fdabdc80c208a521c47e50b136d5babb1..0f32ef31ea9a40eaea934a001350bedbc2155cf6 100644 --- a/modules/gui/pymod/export_gosty.cc +++ b/modules/gui/pymod/export_gosty.cc @@ -27,7 +27,6 @@ using namespace boost::python; #include <ost/gui/perspective.hh> #include <ost/gui/python_shell/python_shell.hh> #include <ost/gui/scene_win/scene_win.hh> -#include <ost/gui/sequence_viewer/sequence_viewer.hh> #include <ost/gui/tools/tool_options_win.hh> #include "transfer_ownership.hh" @@ -96,10 +95,6 @@ void export_Gosty() return_value_policy<reference_existing_object>()) .add_property("seq_viewer", make_function(&GostyApp::GetSequenceViewer, return_value_policy<reference_existing_object>())) - .def("GetSequenceViewerV2", &GostyApp::GetSequenceViewerV2, - return_value_policy<reference_existing_object>()) - .add_property("seq_viewer_v2", make_function(&GostyApp::GetSequenceViewerV2, - return_value_policy<reference_existing_object>())) .def("GetToolOptionsWin", &GostyApp::GetToolOptionsWin, return_value_policy<reference_existing_object>()) .add_property("tool_options_win", make_function(&GostyApp::GetToolOptionsWin, diff --git a/modules/gui/pymod/export_overlay.cc b/modules/gui/pymod/export_overlay.cc index d5293ddd01be9df97d9afc52ec3fb0aa4a9c0f45..4a19bceeb30e06a5e9e0737b64b53c0210dc7fd1 100644 --- a/modules/gui/pymod/export_overlay.cc +++ b/modules/gui/pymod/export_overlay.cc @@ -118,8 +118,8 @@ void export_overlay() .def("ClearMask",&MaskOverlay::ClearMask) .def("GetShift",&MaskOverlay::GetShift) .def("ClearShift",&MaskOverlay::ClearShift) - // .def("SetShift",&MaskOverlay::SetShift) - // .def("ApplyShiftToMask",&MaskOverlay::ApplyShiftToMask) + .def("SetShift",&MaskOverlay::SetShift) + .def("ApplyShiftToMask",&MaskOverlay::ApplyShiftToMask) ; /* class_<Gauss2DOverlay,bases<Overlay>,boost::noncopyable>("Gauss2DOverlay",init<const alg::ParamsGauss2D&>()) diff --git a/modules/gui/pymod/export_sequence_viewer.cc b/modules/gui/pymod/export_sequence_viewer.cc index e6127166c5cb2c23903b9d407ad7437959c0addb..32e79ed48d3eb9e90f0f8aa5aa072388907c4e22 100644 --- a/modules/gui/pymod/export_sequence_viewer.cc +++ b/modules/gui/pymod/export_sequence_viewer.cc @@ -16,7 +16,10 @@ // along with this library; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA //------------------------------------------------------------------------------ +#include <vector> + #include <boost/python.hpp> +#include <boost/python/suite/indexing/vector_indexing_suite.hpp> #include <ost/gui/sequence_viewer/sequence_viewer.hh> @@ -26,12 +29,88 @@ using namespace boost::python; using namespace ost; using namespace ost::gui; +namespace { + +void change_display_mode_a(SequenceViewer* seq_viewer, const QString& mode) +{ + seq_viewer->ChangeDisplayMode(mode); +} + +void change_display_mode_b(SequenceViewer* seq_viewer, const gfx::EntityP& entity, const QString& mode) +{ + seq_viewer->ChangeDisplayMode(entity, mode); +} + +void change_display_mode_c(SequenceViewer* seq_viewer, const seq::AlignmentHandle& alignment, const QString& mode) +{ + seq_viewer->ChangeDisplayMode(alignment, mode); +} + +String get_current_display_mode_a(SequenceViewer* seq_viewer) +{ + return seq_viewer->GetCurrentDisplayMode().toStdString(); +} + +String get_current_display_mode_b(SequenceViewer* seq_viewer, const gfx::EntityP& entity) +{ + return seq_viewer->GetCurrentDisplayMode(entity).toStdString(); +} + +String get_current_display_mode_c(SequenceViewer* seq_viewer, const seq::AlignmentHandle& alignment) +{ + return seq_viewer->GetCurrentDisplayMode(alignment).toStdString(); +} + +std::vector<String> get_display_modes_a(SequenceViewer* seq_viewer) +{ + std::vector<String> modes; + const QStringList& list = seq_viewer->GetDisplayModes(); + for (int i=0; i<list.size(); i++){ + modes.push_back(list.at(i).toStdString()); + } + return modes; +} + +std::vector<String> get_display_modes_b(SequenceViewer* seq_viewer, const gfx::EntityP& entity) +{ + std::vector<String> modes; + const QStringList& list = seq_viewer->GetDisplayModes(entity); + for (int i=0; i<list.size(); i++){ + modes.push_back(list.at(i).toStdString()); + } + return modes; +} + +std::vector<String> get_display_modes_c(SequenceViewer* seq_viewer, const seq::AlignmentHandle& alignment) +{ + std::vector<String> modes; + const QStringList& list = seq_viewer->GetDisplayModes(alignment); + for (int i=0; i<list.size(); i++){ + modes.push_back(list.at(i).toStdString()); + } + return modes; +} + +} + void export_SequenceViewer() { - class_<SequenceViewer, boost::noncopyable >("SequenceViewer", no_init) + class_<SequenceViewer, boost::noncopyable >("SequenceViewer",init<>()) + .def(init<bool, optional<QWidget*> >()) .def("Show", &SequenceViewer::show) .def("Hide", &SequenceViewer::hide) + .def("AddAlignment", &SequenceViewer::AddAlignment) + .def("RemoveAlignment", &SequenceViewer::RemoveAlignment) + .def("GetDisplayModes", &get_display_modes_a) + .def("GetDisplayModes", &get_display_modes_b) + .def("GetDisplayModes", &get_display_modes_c) + .def("GetCurrentDisplayMode", &get_current_display_mode_a) + .def("GetCurrentDisplayMode", &get_current_display_mode_b) + .def("GetCurrentDisplayMode", &get_current_display_mode_c) + .def("ChangeDisplayMode",&change_display_mode_a) + .def("ChangeDisplayMode",&change_display_mode_b) + .def("ChangeDisplayMode",&change_display_mode_c) .def("GetQObject",&get_py_qobject<SequenceViewer>) .add_property("qobject", &get_py_qobject<SequenceViewer>) ; diff --git a/modules/gui/pymod/export_tool.cc b/modules/gui/pymod/export_tool.cc index 73067336468023385aaa0cfd10a673be4126a2f1..946340659ba6bbf7aa8f26c161dd163adffc8124 100644 --- a/modules/gui/pymod/export_tool.cc +++ b/modules/gui/pymod/export_tool.cc @@ -45,7 +45,7 @@ struct WrappedTool : public Tool { try { return call_method<void, MouseEvent>(self, "Click", event); - } catch(error_already_set& e) { + } catch(error_already_set& ) { PyErr_Print(); } } @@ -58,7 +58,7 @@ struct WrappedTool : public Tool { try { return call_method< bool, gfx::NodePtrList >(self, "CanOperateOn", nodes); - } catch(error_already_set& e) { + } catch(error_already_set& ) { PyErr_Print(); } return false; @@ -71,7 +71,7 @@ struct WrappedTool : public Tool String loc = call_method<String>(self, "GetIconPath"); QIcon icon = QIcon(loc.c_str()); return icon; - } catch(error_already_set& e) { + } catch(error_already_set& ) { PyErr_Print(); } QIcon icon = QIcon(); diff --git a/modules/gui/pymod/scene/color_options_widget.py b/modules/gui/pymod/scene/color_options_widget.py index 2683a745dfdf180e4e1ebe1ccbac474342b24d06..7ec80e1a5ecdef5e141f728dbc2f80c648089246 100644 --- a/modules/gui/pymod/scene/color_options_widget.py +++ b/modules/gui/pymod/scene/color_options_widget.py @@ -22,7 +22,15 @@ import sys from ost import mol from ost import gui from ost import gfx +try: + from ost import img + _img_present=True +except ImportError: + _img_present=False + pass + from PyQt4 import QtCore, QtGui +from scene_selection_helper import SelHelper from gradient_editor_widget import GradientEditor from uniform_color_widget import UniformColorWidget from combo_options_widget import ComboOptionsWidget @@ -35,11 +43,15 @@ class ColorOptionsWidget(ComboOptionsWidget): self.text_ = "Color Options" #Add options to menu - self.AddWidget("Color by Element", ByElementWidget("Color by Element")) - self.AddWidget("Color by Chain", ByChainWidget("Color by Chain")) - self.AddWidget("Color by Property", GradientEditor(self)) - self.AddWidget("Uniform",UniformColorWidget(self)) + self.entity_widgets_ = list() + self.entity_widgets_.append(["Color by Element", ByElementWidget("Color by Element")]) + self.entity_widgets_.append(["Color by Chain", ByChainWidget("Color by Chain")]) + self.entity_widgets_.append(["Color by Property", GradientEditor()]) + self.entity_widgets_.append(["Uniform",UniformColorWidget()]) + self.img_widgets_ = list() + self.img_widgets_.append(["Uniform",UniformColorWidget()]) + self.setMinimumSize(250,200) def DoSomething(self, item): @@ -57,19 +69,31 @@ class ColorOptionsWidget(ComboOptionsWidget): def Update(self): + ComboOptionsWidget.setEnabled(self,True) - scene_selection = gui.SceneSelection.Instance() - if scene_selection.GetActiveNodeCount() == 0 and scene_selection.GetActiveViewCount() == 0: + if SelHelper().CheckAllFlags(SelHelper.NO_SELECTION): ComboOptionsWidget.setEnabled(self,False) return - - for i in range(0,scene_selection.GetActiveNodeCount()): - node = scene_selection.GetActiveNode(i) - if not (isinstance(node, gfx.Entity) or isinstance(node, gfx.Surface)): - ComboOptionsWidget.setEnabled(self,False) - return - + + for w in self.entity_widgets_: + self.RemoveWidget(w[0]) + for w in self.img_widgets_: + self.RemoveWidget(w[0]) + + + if SelHelper().CheckFlags(SelHelper.HAS_IMG | SelHelper.IS_ONE_TYPE): + for w in self.img_widgets_: + self.AddWidget(w[0], w[1]) + elif SelHelper().CheckMinOneFlag(SelHelper.HAS_ENTITY| SelHelper.HAS_VIEW| SelHelper.HAS_SURFACE) and SelHelper().CheckNotFlags(SelHelper.HAS_IMG): + for w in self.entity_widgets_: + self.AddWidget(w[0], w[1]) + else: + ComboOptionsWidget.setEnabled(self,False) + return + + self.GetCurrentWidget().Update() + def GetText(self): return self.text_ diff --git a/modules/gui/pymod/scene/color_select_widget.py b/modules/gui/pymod/scene/color_select_widget.py index a02986b7b92d1a6ab4684ff5689a2a8f447169b5..b8de8bf042bf8dc048c9f0ac02406f2734bba49e 100644 --- a/modules/gui/pymod/scene/color_select_widget.py +++ b/modules/gui/pymod/scene/color_select_widget.py @@ -59,11 +59,19 @@ class ColorSelectWidget(QtGui.QWidget): def GetColor(self): return self.color_ + def GetGfxColor(self): + color = self.GetColor() + return gfx.Color(color.redF(), color.greenF(), color.blueF()) + def SetColor(self, color): if(self.color_ != color): self.color_ = color self.emit(QtCore.SIGNAL("colorChanged")) self.update() + + def SetGfxColor(self, color): + qcolor= QtGui.QColor(color.Red()*255,color.Green()*255,color.Blue()*255,color.Alpha()*255) + self.SetColor(qcolor) def paintEvent(self, event): if self.isEnabled(): diff --git a/modules/gui/pymod/scene/combo_options_widget.py b/modules/gui/pymod/scene/combo_options_widget.py index dea16f03730573a16f4ea2e542e12b44395a12b5..b84630cc1bfd94f42b15d5f09904e73fada359d1 100644 --- a/modules/gui/pymod/scene/combo_options_widget.py +++ b/modules/gui/pymod/scene/combo_options_widget.py @@ -81,7 +81,7 @@ class ComboOptionsWidget(QtGui.QWidget): def RemoveWidget(self,ident): index = self.__GetIndex(ident) if(index >= 0): - self.stacked_widget_.removeWidget(self.combo_box_.itemData().toPyObject()[1]) + self.stacked_widget_.removeWidget(self.combo_box_.itemData(index).toPyObject()[1]) self.combo_box_.removeItem(index) def DoSomething(self, item): @@ -103,7 +103,9 @@ class ComboOptionsWidget(QtGui.QWidget): self.__UpdateView(None) def GetCurrentWidget(self): - return self.__GetCurrentPair()[1] + if(self.combo_box_.currentIndex() >= 0): + return self.__GetCurrentPair()[1] + return None def DoResize(self): item = self.GetCurrentWidget() @@ -127,7 +129,7 @@ class ComboOptionsWidget(QtGui.QWidget): def __GetIndex(self, ident): for i in range(self.combo_box_.count()): pair = self.combo_box_.itemData(i).toPyObject() - if ident == pair[0] and i != self.combo_box_.currentIndex(): + if ident == pair[0]: return i return -1 diff --git a/modules/gui/pymod/scene/inspector_widget.py b/modules/gui/pymod/scene/inspector_widget.py index 4e7e7f76155f5c51219aaae95daa91967b3e6f03..25082a26709ad32bbfcf7b4950f0491198243c3d 100644 --- a/modules/gui/pymod/scene/inspector_widget.py +++ b/modules/gui/pymod/scene/inspector_widget.py @@ -28,7 +28,8 @@ from toolbar_options_widget import ToolBarOptionsWidget from render_options_widget import RenderOptionsWidget from color_options_widget import ColorOptionsWidget from ost.gui.scene.scene_observer_impl import SceneObserverImpl -from preset_widget import PresetWidget +from map_level_widget import AdditionalSettingsWidget +from scene_selection_helper import SelHelper class InspectorWidget(ToolBarOptionsWidget): ICONS_PATH = os.path.join(ost.GetSharedDataPath(), "scene", "icons/") @@ -38,7 +39,7 @@ class InspectorWidget(ToolBarOptionsWidget): options = [ [InspectorWidget.ICONS_PATH+"render_icon.png",RenderOptionsWidget(self),None], [InspectorWidget.ICONS_PATH+"color_icon.png",ColorOptionsWidget(self),None], - [InspectorWidget.ICONS_PATH+"preset_icon.png", PresetWidget(self),None], + [InspectorWidget.ICONS_PATH+"preset_icon.png", AdditionalSettingsWidget(self),"Additional Node Settings"], [InspectorWidget.ICONS_PATH+"tool_icon.png",app.tool_options_win.qobject,"Tool Options"] ] for o in options: @@ -46,8 +47,7 @@ class InspectorWidget(ToolBarOptionsWidget): self.obs = SceneObserverImpl() self.obs.AttachObserver(self) - ost.scene.AttachObserver(self.obs) - self.scene_selection_ = gui.SceneSelection.Instance() + ost.scene.AttachObserver(self.obs) QtCore.QObject.connect(app.scene_win.qobject,QtCore.SIGNAL("ActiveNodesChanged()"), self.ActiveNodesChanged) @@ -58,15 +58,19 @@ class InspectorWidget(ToolBarOptionsWidget): #Observer Methods def NodeRemoved(self, node): + SelHelper().Update() ToolBarOptionsWidget.Update(self) def RenderModeChanged(self, node): + SelHelper().Update() ToolBarOptionsWidget.Update(self) def NodeChanged(self, node): + SelHelper().Update() ToolBarOptionsWidget.Update(self) def ActiveNodesChanged(self): + SelHelper().Update() ToolBarOptionsWidget.Update(self) class InspectorDialog(QtGui.QDialog): diff --git a/modules/gui/pymod/scene/map_level_widget.py b/modules/gui/pymod/scene/map_level_widget.py new file mode 100644 index 0000000000000000000000000000000000000000..fd4f4d15affd6dab5e318b04357328632be28383 --- /dev/null +++ b/modules/gui/pymod/scene/map_level_widget.py @@ -0,0 +1,246 @@ +#------------------------------------------------------------------------------ +# This file is part of the OpenStructure project <www.openstructure.org> +# +# Copyright (C) 2008-2010 by the OpenStructure authors +# +# This library is free software; you can redistribute it and/or modify it under +# the terms of the GNU Lesser General Public License as published by the Free +# Software Foundation; either version 3.0 of the License, or (at your option) +# any later version. +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +#------------------------------------------------------------------------------ +# -*- coding: utf-8 -*- +import math +from ost import gui +from ost import gfx +try: + from ost import img + _img_present=True +except ImportError: + _img_present=False + pass +from PyQt4 import QtCore, QtGui + +from preset_widget import PresetWidget + +class AdditionalSettingsWidget(QtGui.QStackedWidget): + def __init__(self, parent=None): + QtGui.QStackedWidget.__init__(self, parent) + self.map_widget_ = MapLevelWidget(self) + self.preset_widget_ = PresetWidget(self) + self.addWidget(self.preset_widget_); + self.addWidget(self.map_widget_); + self.setContentsMargins(0,0,0,0) + self.setMinimumSize(self.preset_widget_.minimumSize()) + + def Update(self): + self.setEnabled(True) + scene_selection = gui.SceneSelection.Instance() + all_img = True + all_entity = True + for i in range(0,scene_selection.GetActiveNodeCount()): + node = scene_selection.GetActiveNode(i) + if not (isinstance(node, gfx.Entity) or isinstance(node, gfx.Surface)): + all_entity = False + if (not _img_present) or (not isinstance(node, gfx.MapIso)): + all_img = False + if all_img: + self.map_widget_.Update() + self.setMinimumSize(self.map_widget_.minimumSize()) + self.resize(self.map_widget_.minimumSize()) + self.setMinimumSize(self.map_widget_.minimumSize()) + self.setCurrentWidget(self.map_widget_) + elif all_entity: + self.preset_widget_.Update() + self.setMinimumSize(self.preset_widget_.minimumSize()) + self.resize(self.preset_widget_.minimumSize()) + self.setMinimumSize(self.preset_widget_.minimumSize()) + self.setCurrentWidget(self.preset_widget_) + else: + self.setEnabled(False) + +#Map Level Widget +class MapLevelWidget(QtGui.QWidget): + def __init__(self, parent=None): + QtGui.QWidget.__init__(self, parent) + + #Create Ui elements + map_level_label = QtGui.QLabel("Map Contour Level") + font = map_level_label.font() + font.setBold(True) + + self.level_preview_ = LevelPreview() + + self.level_spinbox_ = QtGui.QDoubleSpinBox() + self.level_spinbox_.setDecimals(3) + self.level_spinbox_.setSingleStep(0.05) + + grid = QtGui.QGridLayout() + grid.setContentsMargins(0,5,0,0) + grid.addWidget(self.level_preview_, 0, 0, 1, 4) + grid.addWidget(map_level_label, 1, 0, 1, 3) + grid.addWidget(self.level_spinbox_,1,3,1,1) + grid.setRowStretch(3, 1) + self.setLayout(grid) + + QtCore.QObject.connect(self.level_preview_, QtCore.SIGNAL("levelUpdated"), self.UpdateLevel) + QtCore.QObject.connect(self.level_preview_, QtCore.SIGNAL("levelModified"), self.ModifySpinBox) + QtCore.QObject.connect(self.level_spinbox_, QtCore.SIGNAL("valueChanged(double)"), self.UpdateLevel) + + self.setMinimumSize(250,200) + + def Update(self): + scene_selection = gui.SceneSelection.Instance() + if(scene_selection.GetActiveNodeCount()==1): + node = scene_selection.GetActiveNode(0) + if _img_present and isinstance(node, gfx.MapIso): + self.level_preview_.SetBins(node.GetHistogram()) + self.level_preview_.SetMinimum(node.GetMinLevel()) + self.level_spinbox_.setMinimum(node.GetMinLevel()) + self.level_preview_.SetMaximum(node.GetMaxLevel()) + self.level_spinbox_.setMaximum(node.GetMaxLevel()) + self.level_preview_.SetLevel(node.GetLevel()) + self.setEnabled(True) + else: + self.setEnabled(False) + else: + self.setEnabled(False) + + def UpdateLevel(self, level): + scene_selection = gui.SceneSelection.Instance() + if(scene_selection.GetActiveNodeCount()==1): + node = scene_selection.GetActiveNode(0) + node.SetLevel(level) + + def ModifySpinBox(self, level): + QtCore.QObject.disconnect(self.level_spinbox_, QtCore.SIGNAL("valueChanged(double)"), self.UpdateLevel) + self.level_spinbox_.setValue(level) + QtCore.QObject.connect(self.level_spinbox_, QtCore.SIGNAL("valueChanged(double)"), self.UpdateLevel) + +#Level Preview +class LevelPreview(QtGui.QWidget): + def __init__(self, parent=None): + QtGui.QWidget.__init__(self, parent) + + #Defaults + self.border_offset_ = 3 + self.preview_height_ = 150 + QtGui.QWidget.__init__(self, parent) + + #Ui + self.setMinimumSize(0, self.preview_height_ + 4) + + self.bins_ = None + self.level_ = 0 + self.minimum_ = 0 + self.maximum_ = 0 + + self.paint_mouse_=False + + def SetBins(self, bins): + self.bins_ = bins + self.update() + + def SetMaximum(self, max): + self.maximum_ = max + + def SetMinimum(self, min): + self.minimum_ = min + + def SetLevel(self, level): + self.level_ = level + + def GetLevel(self): + return self.level_ + + def paintEvent(self, event): + if self.isEnabled() and self.bins_ is not None: + painter = QtGui.QPainter() + if painter.begin(self): + self.PaintBackground(painter) + self.PaintBins(painter) + self.PaintLevel(painter) + if(self.paint_mouse_): + self.PaintMouse(painter) + painter.end() + + def PaintBackground(self,painter): + size = self.size() + painter.setBrush(QtCore.Qt.white) + painter.setPen(QtCore.Qt.white) + painter.drawRect(self.border_offset_, + self.border_offset_, + size.width() - 2 * self.border_offset_, + self.preview_height_) + + def PaintBins(self,painter): + size = self.size() + bin_cnt = len(self.bins_) + bin_width = (size.width()-2* self.border_offset_) / float(bin_cnt) + max=0 + for b in self.bins_: + if(b>max): + max = b + max = math.log(max) + if(max > 0): + painter.setBrush(QtCore.Qt.black) + painter.setPen(QtCore.Qt.black) + for i in range(0,bin_cnt): + bin_height = self.bins_[i] + if(bin_height>0): + bin_height = math.floor((math.log(bin_height)/max)*(self.preview_height_-2*(self.border_offset_))) + painter.drawRect(self.border_offset_ + (i*bin_width), + self.preview_height_ - bin_height, + bin_width, + bin_height) + + def PaintLevel(self,painter): + size = self.size() + width = size.width()-(2* self.border_offset_) + tot_len = self.maximum_-self.minimum_ + if(tot_len>0): + cur_len = self.level_-self.minimum_ + painter.setBrush(QtCore.Qt.red) + painter.setPen(QtCore.Qt.red) + painter.drawRect((width / tot_len) * cur_len, + self.border_offset_, + 1, + self.preview_height_) + + def PaintMouse(self,painter): + size = self.size() + width = size.width()-(2* self.border_offset_) + painter.setBrush(QtCore.Qt.gray) + painter.setPen(QtCore.Qt.gray) + pos=self.mapFromGlobal(QtGui.QCursor.pos()) + painter.drawRect(pos.x(), + self.border_offset_, + 1, + self.preview_height_) + + def mouseReleaseEvent(self, event): + self.paint_mouse_=False + size = self.size() + width = size.width()-(2* self.border_offset_) + tot_len = self.maximum_-self.minimum_ + self.level_ = self.minimum_ + float(event.x())/width * tot_len + self.update() + self.emit(QtCore.SIGNAL("levelUpdated"),(self.level_)) + + def mousePressEvent(self,event): + self.paint_mouse_=True + + def mouseMoveEvent(self, event): + size = self.size() + width = size.width()-(2* self.border_offset_) + tot_len = self.maximum_-self.minimum_ + level = self.minimum_ + float(event.x())/width * tot_len + self.emit(QtCore.SIGNAL("levelModified"),(level)) + self.update() \ No newline at end of file diff --git a/modules/gui/pymod/scene/preset_widget.py b/modules/gui/pymod/scene/preset_widget.py index d581a38ea137c80a16baaf07584f8ed81f25986d..dc97b10f78d5d0be6700b9b435e3702cdf7f9833 100644 --- a/modules/gui/pymod/scene/preset_widget.py +++ b/modules/gui/pymod/scene/preset_widget.py @@ -23,6 +23,7 @@ import ost import os from datetime import datetime from PyQt4 import QtCore, QtGui +from scene_selection_helper import SelHelper from preset_list_model import PresetListModel from preset_editor_widget import PresetEditor from preset import Preset @@ -67,7 +68,7 @@ class PresetWidget(QtGui.QWidget): QtCore.QObject.connect(self.list_view_, QtCore.SIGNAL("doubleClicked(const QModelIndex)"), self.Load) - self.setMinimumSize(250,150) + self.setMinimumSize(250,200) def CreateImmutableContextMenu(self): self.immucontext_menu_ = QtGui.QMenu("Context menu", self) @@ -145,16 +146,13 @@ class PresetWidget(QtGui.QWidget): def Update(self): self.setEnabled(True) - scene_selection = gui.SceneSelection.Instance() - if scene_selection.GetActiveNodeCount() == 0: + if SelHelper().CheckAllFlags(SelHelper.NO_SELECTION): self.setEnabled(False) return - for i in range(0,scene_selection.GetActiveNodeCount()): - entity = scene_selection.GetActiveNode(i) - if not isinstance(scene_selection.GetActiveNode(i), gfx.Entity): - self.setEnabled(False) - return + if SelHelper().CheckNotFlags(SelHelper.HAS_ENTITY | SelHelper.IS_ONE_TYPE): + self.setEnabled(False) + return def Rename(self): if(self.list_view_.currentIndex().isValid()): diff --git a/modules/gui/pymod/scene/render_mode_widget.py b/modules/gui/pymod/scene/render_mode_widget.py index 68150543a8e39cea5203021e4977590c3c8a99fe..271ae6699b22c4c90a06876e5867e44f61b2f229 100644 --- a/modules/gui/pymod/scene/render_mode_widget.py +++ b/modules/gui/pymod/scene/render_mode_widget.py @@ -44,7 +44,7 @@ class RenderModeWidget(QtGui.QWidget): scene_selection = gui.SceneSelection.Instance() if scene_selection.GetActiveNodeCount() == 0 and scene_selection.GetActiveViewCount() == 0: - ComboOptionsWidget.setEnabled(self,False) + self.setEnabled(False) return if scene_selection.GetActiveNodeCount() > 0 : @@ -53,7 +53,7 @@ class RenderModeWidget(QtGui.QWidget): if isinstance(entity, gfx.Entity): self.entities_.add(entity) else: - ComboOptionsWidget.setEnabled(self,False) + self.setEnabled(False) return if scene_selection.GetActiveViewCount() > 0 : diff --git a/modules/gui/pymod/scene/render_options_widget.py b/modules/gui/pymod/scene/render_options_widget.py index 4b61a12166713e17f21888350171b1577806a778..cc22f3cc1f28f035b1fc4710872cca5f663cc9cc 100644 --- a/modules/gui/pymod/scene/render_options_widget.py +++ b/modules/gui/pymod/scene/render_options_widget.py @@ -21,7 +21,15 @@ import sys from ost import gui from ost import gfx +try: + from ost import img + from wireframe_widget import WireframeWidget + _img_present=True +except ImportError: + _img_present=False + pass from PyQt4 import QtCore, QtGui +from scene_selection_helper import SelHelper from combo_options_widget import ComboOptionsWidget from custom_widget import CustomWidget from cpk_widget import CPKWidget @@ -50,34 +58,41 @@ class RenderOptionsWidget(ComboOptionsWidget): self.grid_layout_.addWidget(self.stacked_widget_, 1, 0, 1, 2) #Add options to menu - ComboOptionsWidget.AddWidget(self, "", EmptyMode()) - ComboOptionsWidget.AddWidget(self, gfx.RenderMode.SIMPLE, SimpleWidget(self)) - ComboOptionsWidget.AddWidget(self, gfx.RenderMode.CUSTOM, CustomWidget(self)) - ComboOptionsWidget.AddWidget(self, gfx.RenderMode.CPK, CPKWidget(self)) - ComboOptionsWidget.AddWidget(self, gfx.RenderMode.LINE_TRACE, LineTraceWidget(self)) - ComboOptionsWidget.AddWidget(self, gfx.RenderMode.TRACE, TraceWidget(self)) - ComboOptionsWidget.AddWidget(self, gfx.RenderMode.SLINE, SlineWidget(self)) - ComboOptionsWidget.AddWidget(self, gfx.RenderMode.TUBE, TubeWidget(self)) - ComboOptionsWidget.AddWidget(self, gfx.RenderMode.HSC, HSCWidget(self)) + self.entity_widgets_ = list() + self.entity_widgets_.append(["", EmptyMode()]) + self.entity_widgets_.append([gfx.RenderMode.SIMPLE, SimpleWidget()]) + self.entity_widgets_.append([gfx.RenderMode.CUSTOM, CustomWidget()]) + self.entity_widgets_.append([gfx.RenderMode.CPK, CPKWidget()]) + self.entity_widgets_.append([gfx.RenderMode.LINE_TRACE, LineTraceWidget()]) + self.entity_widgets_.append([gfx.RenderMode.TRACE, TraceWidget()]) + self.entity_widgets_.append([gfx.RenderMode.SLINE, SlineWidget()]) + self.entity_widgets_.append([gfx.RenderMode.TUBE, TubeWidget()]) + self.entity_widgets_.append([gfx.RenderMode.HSC, HSCWidget()]) + self.img_widgets_ = list() + if _img_present: + self.img_widgets_.append(["", EmptyMode()]) + self.img_widgets_.append([gfx.RenderMode.SIMPLE, WireframeWidget()]) + self.img_widgets_.append([gfx.RenderMode.FILL, EmptyMode("Fill",gfx.RenderMode.FILL)]) + + self._in_view_method = False self.setMinimumSize(250,200) def DoSomething(self, item): scene_selection = gui.SceneSelection.Instance() for i in range(0,scene_selection.GetActiveNodeCount()): node = scene_selection.GetActiveNode(i) - if isinstance(node, gfx.Entity): + if isinstance(node, gfx.Entity) or (_img_present and isinstance(node, gfx.MapIso)): render_mode = item.GetRenderMode() if render_mode is not None: node.SetRenderMode(render_mode) if(scene_selection.GetActiveViewCount() > 0): entity = scene_selection.GetViewEntity() - for i in range(0,scene_selection.GetActiveViewCount()): - view = scene_selection.GetActiveView(i) - render_mode = item.GetRenderMode() - if render_mode is not None: - entity.SetRenderMode(item.GetRenderMode(),view,self.keep_action_.isChecked()) + view = scene_selection.GetViewUnion() + render_mode = item.GetRenderMode() + if render_mode is not None: + entity.SetRenderMode(item.GetRenderMode(),view,self.keep_action_.isChecked()) item.Update() self.DoResize() @@ -85,49 +100,85 @@ class RenderOptionsWidget(ComboOptionsWidget): def Update(self): if hasattr(self, "keep_button_"): self.keep_button_.setEnabled(True) - scene_selection = gui.SceneSelection.Instance() - if scene_selection.GetActiveNodeCount() == 0 and scene_selection.GetActiveViewCount() == 0: + + ComboOptionsWidget.setEnabled(self,True) + + cur_widget = self.GetCurrentWidget() + new_render_mode = None + if cur_widget is not None: + new_render_mode = cur_widget.GetRenderMode() + + if SelHelper().CheckAllFlags(SelHelper.NO_SELECTION): ComboOptionsWidget.setEnabled(self,False) return + if not self._in_view_method: + for w in self.entity_widgets_: + self.RemoveWidget(w[0]) + for w in self.img_widgets_: + self.RemoveWidget(w[0]) + + scene_selection = gui.SceneSelection.Instance() if scene_selection.GetActiveNodeCount() > 0 : if hasattr(self, "keep_button_"): self.keep_button_.setEnabled(False) render_mode_valid = True render_mode = None for i in range(0,scene_selection.GetActiveNodeCount()): - entity = scene_selection.GetActiveNode(i) - if isinstance(scene_selection.GetActiveNode(i), gfx.Entity): + node = scene_selection.GetActiveNode(i) + if isinstance(scene_selection.GetActiveNode(i), gfx.GfxObj): if render_mode is None: - render_mode = entity.GetRenderMode() - elif render_mode != entity.GetRenderMode(): + render_mode = node.GetRenderMode() + elif render_mode != node.GetRenderMode(): render_mode_valid = False - break - else: - ComboOptionsWidget.setEnabled(self,False) - return + + if SelHelper().CheckFlags(SelHelper.HAS_IMG | SelHelper.IS_ONE_TYPE): + for w in self.img_widgets_: + self.AddWidget(w[0], w[1]) + elif SelHelper().CheckMinOneFlag(SelHelper.HAS_ENTITY| SelHelper.HAS_VIEW) and SelHelper().CheckNotFlags(SelHelper.HAS_IMG): + if not self._in_view_method: + for w in self.entity_widgets_: + self.AddWidget(w[0], w[1]) + else: + ComboOptionsWidget.setEnabled(self,False) + return + + if SelHelper().CheckMinOneFlag(SelHelper.HAS_ENTITY| SelHelper.HAS_IMG) and SelHelper().CheckNotFlags(SelHelper.HAS_VIEW): if(render_mode_valid): ComboOptionsWidget.ChangeSelectedItem(self,render_mode) else: ComboOptionsWidget.ChangeSelectedItem(self,"") - + else: + if not self._in_view_method: + self._in_view_method = True + ComboOptionsWidget.ChangeSelectedItem(self,new_render_mode) self.GetCurrentWidget().Update() - - ComboOptionsWidget.setEnabled(self,True) - + def GetText(self): return self.text_ class EmptyMode(QtGui.QWidget): - def __init__(self, parent=None): + def __init__(self, text="", render_mode=None, parent=None): QtGui.QLabel.__init__(self, parent) self.setMinimumSize(250,30) - + self.text = text + self.render_mode = render_mode + if(render_mode): + text_label = QtGui.QLabel(text) + font = text_label.font() + font.setBold(True) + grid = QtGui.QGridLayout() + grid.addWidget(text_label,0,0,1,1) + grid.addWidget(QtGui.QLabel("No Settings available"), 1, 0, 1, 3) + grid.setRowStretch(2,1) + self.setLayout(grid) + self.setMinimumSize(250,60) + def Update(self): True #Do Nothing def GetText(self): - return "" + return self.text def GetRenderMode(self): - return None + return self.render_mode diff --git a/modules/gui/pymod/scene/scene_selection_helper.py b/modules/gui/pymod/scene/scene_selection_helper.py new file mode 100644 index 0000000000000000000000000000000000000000..0dc43312ca21b96752ebf56718aaa9eb12c6a692 --- /dev/null +++ b/modules/gui/pymod/scene/scene_selection_helper.py @@ -0,0 +1,106 @@ +#------------------------------------------------------------------------------ +# This file is part of the OpenStructure project <www.openstructure.org> +# +# Copyright (C) 2008-2010 by the OpenStructure authors +# +# This library is free software; you can redistribute it and/or modify it under +# the terms of the GNU Lesser General Public License as published by the Free +# Software Foundation; either version 3.0 of the License, or (at your option) +# any later version. +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +#------------------------------------------------------------------------------ + +import sys +from ost import gui +import sip +from ost import gfx +import ost +import os +try: + from ost import img + _img_present=True +except ImportError: + _img_present=False + pass + +class SelHelper(): + __shared_state = {} + + NO_SELECTION = 0 + HAS_ENTITY = 1 + HAS_VIEW = 2 + HAS_IMG = 4 + HAS_SURFACE = 8 + IS_ONE_TYPE = 16 + IS_MULTI_TYPE = 32 + SINGLE_SELECTION = 64 + MULTI_SELECTION = 128 + + def __init__(self): + self.__dict__ = self.__shared_state + if not '_ready' in dir(self): + self.scene_sel_ = gui.SceneSelection.Instance() + self.current_flags_ = 0 + self._ready = True + + def Update(self): + self.current_flags_ = 0 + if self.scene_sel_.GetActiveNodeCount() == 0 and self.scene_sel_.GetActiveViewCount() == 0: + return + + for i in range(0,self.scene_sel_.GetActiveNodeCount()): + node = self.scene_sel_.GetActiveNode(i) + if isinstance(node, gfx.Entity): + self.current_flags_ = self.current_flags_ | SelHelper.HAS_ENTITY + if isinstance(node, gfx.Surface): + self.current_flags_ = self.current_flags_ | SelHelper.HAS_SURFACE + if (_img_present) and isinstance(node, gfx.MapIso): + self.current_flags_ = self.current_flags_ | SelHelper.HAS_IMG + + if self.scene_sel_.GetActiveViewCount() > 0: + self.current_flags_ = self.current_flags_ | SelHelper.HAS_VIEW + + cnt = 0 + if self.current_flags_ & SelHelper.HAS_ENTITY: + cnt += 1 + if self.current_flags_ & SelHelper.HAS_SURFACE: + cnt += 1 + if self.current_flags_ & SelHelper.HAS_IMG: + cnt += 1 + if self.current_flags_ & SelHelper.HAS_VIEW: + cnt += 1 + + if cnt == 1: + self.current_flags_ = self.current_flags_ | SelHelper.IS_ONE_TYPE + elif cnt > 1: + self.current_flags_ = self.current_flags_ | SelHelper.IS_MULTI_TYPE + + if self.scene_sel_.GetActiveNodeCount()==1: + self.current_flags_ = self.current_flags_ | SelHelper.SINGLE_SELECTION + elif self.scene_sel_.GetActiveNodeCount()>1: + self.current_flags_ = self.current_flags_ | SelHelper.MULTI_SELECTION + + def CheckAllFlags(self, flags): + if(flags == self.current_flags_ & flags) and (flags == self.current_flags_ | flags): + return True + return False + + def CheckNotFlags(self, flags): + return not self.CheckFlags(flags) + + def CheckFlags(self, flags): + if(flags == self.current_flags_ & flags): + return True + return False + + def CheckMinOneFlag(self, flags): + if((self.current_flags_ - (self.current_flags_ & flags)) < self.current_flags_): + return True + return False diff --git a/modules/gui/pymod/scene/toolbar_options_widget.py b/modules/gui/pymod/scene/toolbar_options_widget.py index 006c09b160ba710c83d15679706c1ff20aa4cbf2..d331b62b4cd15d5b5ddfc22f83c2b5fbb13951e1 100644 --- a/modules/gui/pymod/scene/toolbar_options_widget.py +++ b/modules/gui/pymod/scene/toolbar_options_widget.py @@ -126,13 +126,13 @@ class ToolBarOptionsWidget(QtGui.QWidget): self.current_action_ = action widget = action.data().toPyObject()[1] self.stackedWidget.setCurrentWidget(widget) - self.DoSomething(widget) if hasattr(widget, "Update"): widget.Update() if(self.current_action_ == action): self.current_action_.setChecked(True) else: self.current_action_=action + self.DoSomething(widget) #Private Methods def __GetCurrentWidget(self): return self.stackedWidget.currentWidget(); diff --git a/modules/gui/pymod/scene/uniform_color_widget.py b/modules/gui/pymod/scene/uniform_color_widget.py index ff2cdc2ddfcd52a0a0ea828f812c2d161e176f32..b5c074c9c89d70aaa5ed9b5eaa582a171b3da672 100644 --- a/modules/gui/pymod/scene/uniform_color_widget.py +++ b/modules/gui/pymod/scene/uniform_color_widget.py @@ -21,6 +21,12 @@ from ost import gui from ost import gfx from ost import mol +try: + from ost import img + _img_present=True +except ImportError: + _img_present=False + pass from PyQt4 import QtCore, QtGui from color_select_widget import ColorSelectWidget @@ -52,37 +58,45 @@ class UniformColorWidget(QtGui.QWidget): top_layout.addLayout(grid) self.setLayout(top_layout) - QtCore.QObject.connect(self.color_select_widget_, QtCore.SIGNAL("colorChanged"), self.Update) + QtCore.QObject.connect(self.color_select_widget_, QtCore.SIGNAL("colorChanged"), self.ChangeColors) self.setMinimumSize(250,150) def Update(self): + scene_selection = gui.SceneSelection.Instance() + for i in range(0,scene_selection.GetActiveNodeCount()): + node = scene_selection.GetActiveNode(i) + if _img_present and isinstance(node, gfx.MapIso): + if self.color_select_widget_.GetGfxColor() != node.GetColor(): + self.color_select_widget_.SetGfxColor(node.GetColor()) + else: + self.ChangeColors() + + def ChangeColors(self): scene_selection = gui.SceneSelection.Instance() for i in range(0,scene_selection.GetActiveNodeCount()): node = scene_selection.GetActiveNode(i) self.ChangeColor(node) - + if(scene_selection.GetActiveViewCount() > 0): entity = scene_selection.GetViewEntity() view = scene_selection.GetViewUnion() self.ChangeViewColor(entity,view) - + def ChangeColor(self, node): + gfx_color = self.color_select_widget_.GetGfxColor() if isinstance(node, gfx.Entity) or isinstance(node, gfx.Surface): - gfx_color = self.GetGfxColor() - node.CleanColorOps() - node.SetColor(gfx_color,"") + node.CleanColorOps() + node.SetColor(gfx_color,"") + elif _img_present and isinstance(node, gfx.MapIso): + node.SetColor(gfx_color) def ChangeViewColor(self, entity, view): if isinstance(entity, gfx.Entity) and isinstance(view, mol.EntityView): - gfx_color = self.GetGfxColor() + gfx_color = self.color_select_widget_.GetGfxColor() ufco=gfx.UniformColorOp(mol.QueryViewWrapper(view),gfx_color) entity.Apply(ufco) - - def GetGfxColor(self): - color = self.color_select_widget_.GetColor() - return gfx.Color(color.redF(), color.greenF(), color.blueF()) - + def resizeEvent(self, event): self.color_select_widget_.SetSize(self.width()/2,self.height()/2) diff --git a/modules/gui/pymod/scene/wireframe_widget.py b/modules/gui/pymod/scene/wireframe_widget.py new file mode 100644 index 0000000000000000000000000000000000000000..997003743cc7a6eb564ea542e3c18bf48762713f --- /dev/null +++ b/modules/gui/pymod/scene/wireframe_widget.py @@ -0,0 +1,103 @@ +#------------------------------------------------------------------------------ +# This file is part of the OpenStructure project <www.openstructure.org> +# +# Copyright (C) 2008-2010 by the OpenStructure authors +# +# This library is free software; you can redistribute it and/or modify it under +# the terms of the GNU Lesser General Public License as published by the Free +# Software Foundation; either version 3.0 of the License, or (at your option) +# any later version. +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +#------------------------------------------------------------------------------ +# -*- coding: utf-8 -*- + +from ost import gui +from ost import gfx +from PyQt4 import QtCore, QtGui +try: + from ost import img + _img_present=True +except ImportError: + _img_present=False + pass +from scene_selection_helper import SelHelper + +#Wireframe Options +class WireframeWidget(QtGui.QWidget): + def __init__(self, parent=None): + QtGui.QWidget.__init__(self, parent) + + #Title + self.text_ = "Wireframe" + + #Defaults + min_line_width = 0.01 + max_line_width = 20 + + #Set Render Mode + self.mode_ = gfx.RenderMode.SIMPLE + + #Create Ui elements + self.aa_rendering_cb_ = QtGui.QCheckBox() + + self.radius_spinbox_ = QtGui.QDoubleSpinBox() + self.radius_spinbox_.setRange(min_line_width, max_line_width) + self.radius_spinbox_.setDecimals(2) + self.radius_spinbox_.setSingleStep(0.1) + + simple_label = QtGui.QLabel("Wireframe Settings") + font = simple_label.font() + font.setBold(True) + + radius_label = QtGui.QLabel("Line Width") + aa_label = QtGui.QLabel("AA-Lines") + + grid = QtGui.QGridLayout() + grid.addWidget(simple_label,0,0,1,3) + grid.addWidget(aa_label, 1, 0, 1, 3) + grid.addWidget(self.aa_rendering_cb_, 1, 2, 1, 1) + grid.addWidget(radius_label,2,0,1,3) + grid.addWidget(self.radius_spinbox_,2,2,1,1) + grid.setRowStretch(5,1) + self.setLayout(grid) + + QtCore.QObject.connect(self.radius_spinbox_, QtCore.SIGNAL("valueChanged(double)"), self.UpdateLineWidth) + QtCore.QObject.connect(self.aa_rendering_cb_, QtCore.SIGNAL("stateChanged(int)"), self.UpdateAA) + + self.setMinimumSize(250,100) + + def UpdateAA(self, value): + scene_selection = gui.SceneSelection.Instance() + for i in range(0,scene_selection.GetActiveNodeCount()): + node = scene_selection.GetActiveNode(i) + node.SetAALines(value) + + def UpdateLineWidth(self, value): + scene_selection = gui.SceneSelection.Instance() + for i in range(0,scene_selection.GetActiveNodeCount()): + node = scene_selection.GetActiveNode(i) + node.SetLineWidth(value) + + def UpdateGui(self): + scene_selection = gui.SceneSelection.Instance() + node = scene_selection.GetActiveNode(0) + self.radius_spinbox_.setValue(node.GetLineWidth()) + + def Update(self): + self.setEnabled(True) + self.UpdateGui() + if SelHelper().CheckNotFlags(SelHelper.HAS_IMG | SelHelper.IS_ONE_TYPE): + self.setEnabled(False) + + def GetText(self): + return self.text_ + + def GetRenderMode(self): + return self.mode_ \ No newline at end of file diff --git a/modules/gui/pymod/wrap_gui.cc b/modules/gui/pymod/wrap_gui.cc index 149c7885f69b5b5fb4df54bb63f18104696aae57..4034dfe1cbead9baa952f1d6d2cacea11536191d 100644 --- a/modules/gui/pymod/wrap_gui.cc +++ b/modules/gui/pymod/wrap_gui.cc @@ -33,7 +33,6 @@ void export_Gosty(); void export_PyShell(); void export_SceneWin(); void export_SequenceViewer(); -void export_SequenceViewerV2(); void export_PanelBar(); void export_Perspective(); void export_SipHandler(); @@ -117,7 +116,6 @@ BOOST_PYTHON_MODULE(_gui) export_SceneWin(); export_SceneSelection(); export_SequenceViewer(); - export_SequenceViewerV2(); export_RemoteSiteLoader(); export_FileLoader(); export_Widget(); diff --git a/modules/gui/share/CMakeLists.txt b/modules/gui/share/CMakeLists.txt index d755bcd3a784ad2af217bc54b2456627126a16c5..6b08487687699784398223b61eb72e95b34290dd 100644 --- a/modules/gui/share/CMakeLists.txt +++ b/modules/gui/share/CMakeLists.txt @@ -3,7 +3,9 @@ set(GUI_ICONS icons/add_icon.png icons/close_icon.png icons/distance_icon.png + icons/find_icon.png icons/map_icon.png + icons/menubar_icon.png icons/rigid_body_manipulator_icon.png icons/selection_icon.png icons/show_sidebar_icon.png diff --git a/modules/gui/share/icons/find_icon.png b/modules/gui/share/icons/find_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..39f6331715ea8fce80451c6314e9eac45193dabe Binary files /dev/null and b/modules/gui/share/icons/find_icon.png differ diff --git a/modules/gui/share/icons/menubar_icon.png b/modules/gui/share/icons/menubar_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3e8d988cce14a8ea5f124e7651dbbcfd2b8026fd Binary files /dev/null and b/modules/gui/share/icons/menubar_icon.png differ diff --git a/modules/gui/src/CMakeLists.txt b/modules/gui/src/CMakeLists.txt index 7bee5c2778f74bbbceacc6c5bc7c9e54c9d9ebc7..651079e4929f28e3b0cc73d7ec0dc39794830270 100644 --- a/modules/gui/src/CMakeLists.txt +++ b/modules/gui/src/CMakeLists.txt @@ -12,16 +12,12 @@ side_bar.hh splitter_panel_bar.hh tabbed_panel_bar.hh ) -set(OST_GUI_SEQUENCE_VIEWER_HEADERS -sequence_item.hh -sequence_viewer_base.hh -sequence_viewer.hh -sequence_scene.hh -sequence_search_bar.hh -) -set(OST_GUI_SEQUENCE_VIEW_HEADERS +set(OST_GUI_SEQUENCE_VIEWER_HEADERS +align_properties_painter.hh base_row.hh +background_painter.hh +conservation_painter.hh painter.hh secstr_row.hh seq_secstr_painter.hh @@ -30,11 +26,14 @@ seq_text_painter.hh sequence_delegate.hh sequence_model.hh sequence_row.hh +sequence_search_bar.hh sequence_table_view.hh sequence_viewer.hh tick_painter.hh title_row.hh -view_object.hh +alignment_view_object.hh +base_view_object.hh +sequence_view_object.hh ) set(OST_GUI_TOOLS_HEADERS @@ -209,24 +208,25 @@ scene_menu.cc widget.cc widget_pool.cc remote_site_loader.cc -sequence_viewer/sequence_item.cc -sequence_viewer/sequence_viewer_base.cc -sequence_viewer/sequence_viewer.cc -sequence_viewer/sequence_scene.cc +sequence_viewer/align_properties_painter.cc +sequence_viewer/base_row.cc +sequence_viewer/background_painter.cc +sequence_viewer/conservation_painter.cc +sequence_viewer/secstr_row.cc +sequence_viewer/seq_secstr_painter.cc +sequence_viewer/seq_selection_painter.cc +sequence_viewer/seq_text_painter.cc +sequence_viewer/sequence_delegate.cc +sequence_viewer/sequence_model.cc +sequence_viewer/sequence_row.cc sequence_viewer/sequence_search_bar.cc -sequence/base_row.cc -sequence/secstr_row.cc -sequence/seq_secstr_painter.cc -sequence/seq_selection_painter.cc -sequence/seq_text_painter.cc -sequence/sequence_delegate.cc -sequence/sequence_model.cc -sequence/sequence_row.cc -sequence/sequence_table_view.cc -sequence/sequence_viewer.cc -sequence/tick_painter.cc -sequence/title_row.cc -sequence/view_object.cc +sequence_viewer/sequence_table_view.cc +sequence_viewer/sequence_viewer.cc +sequence_viewer/tick_painter.cc +sequence_viewer/title_row.cc +sequence_viewer/alignment_view_object.cc +sequence_viewer/base_view_object.cc +sequence_viewer/sequence_view_object.cc gosty_app.cc change_process_name.cc main_area.cc @@ -342,25 +342,26 @@ scene_selection.hh widget.hh widget_geom_handler.hh widget_pool.hh -sequence_viewer/sequence_item.hh -sequence_viewer/sequence_viewer_base.hh -sequence_viewer/sequence_viewer.hh -sequence_viewer/sequence_scene.hh +sequence_viewer/align_properties_painter.hh +sequence_viewer/background_painter.hh +sequence_viewer/base_row.hh +sequence_viewer/conservation_painter.hh +sequence_viewer/painter.hh +sequence_viewer/secstr_row.hh +sequence_viewer/seq_secstr_painter.hh +sequence_viewer/seq_selection_painter.hh +sequence_viewer/seq_text_painter.hh +sequence_viewer/sequence_delegate.hh +sequence_viewer/sequence_model.hh +sequence_viewer/sequence_row.hh sequence_viewer/sequence_search_bar.hh -sequence/base_row.hh -sequence/painter.hh -sequence/secstr_row.hh -sequence/seq_secstr_painter.hh -sequence/seq_selection_painter.hh -sequence/seq_text_painter.hh -sequence/sequence_delegate.hh -sequence/sequence_model.hh -sequence/sequence_row.hh -sequence/sequence_table_view.hh -sequence/sequence_viewer.hh -sequence/tick_painter.hh -sequence/title_row.hh -sequence/view_object.hh +sequence_viewer/sequence_table_view.hh +sequence_viewer/sequence_viewer.hh +sequence_viewer/tick_painter.hh +sequence_viewer/title_row.hh +sequence_viewer/alignment_view_object.hh +sequence_viewer/base_view_object.hh +sequence_viewer/sequence_view_object.hh plot_viewer/plot_axis_base.hh plot_viewer/plot_data_graphics_item_base.hh plot_viewer/plot_function_info.hh @@ -470,14 +471,13 @@ module(NAME gui SOURCES ${OST_GUI_MOCS} ${OST_GUI_SOURCES} HEADERS ${OST_GUI_TOOLS_HEADERS} IN_DIR tools ${OST_GUI_PLOT_VIEWER_HEADERS} IN_DIR plot_viewer ${OST_GUI_SEQUENCE_VIEWER_HEADERS} IN_DIR sequence_viewer - ${OST_GUI_SEQUENCE_VIEW_HEADERS} IN_DIR sequence ${OST_GUI_PYTHON_SHELL_HEADERS} IN_DIR python_shell ${OST_GUI_PANEL_BAR_HEADERS} IN_DIR panel_bar ${OST_GUI_SCENE_WIN_HEADERS} IN_DIR scene_win ${OST_GUI_INPUT_HEADERS} ${OST_GUI_DATA_VIEWER_HEADERS} ${OST_GUI_HEADERS} - DEPENDS_ON gfx io mol_alg + DEPENDS_ON gfx io mol_alg seq_alg LINK ${QT_LIBRARIES} ${PYTHON_LIBRARIES} ${BOOST_PYTHON_LIBRARIES} ${SPNAV_LIBRARIES}) include_directories(${PYTHON_INCLUDE_PATH}) qt4_add_resources(OST_QT_RESOURCE dngr.qrc) diff --git a/modules/gui/src/data_viewer/mask_overlay.cc b/modules/gui/src/data_viewer/mask_overlay.cc index a10082a3408b0988c2c38bda0230b6440d7916ff..6e1ae09906d3574d1ac7ebd47498fd08f49be9bb 100644 --- a/modules/gui/src/data_viewer/mask_overlay.cc +++ b/modules/gui/src/data_viewer/mask_overlay.cc @@ -214,5 +214,19 @@ void MaskOverlay::ClearMask() add_mode_=false; } +void MaskOverlay::SetShift(geom::Vec2 shift) +{ + shift_=shift; +} + +void MaskOverlay::ApplyShiftToMask() +{ + for(std::vector<geom::Polygon2>::iterator it=polygons_.begin();it!=polygons_.end();++it){ + (*it)=(*it)+shift_; + } + new_poly_=new_poly_+shift_; + shift_=geom::Vec2(0.0,0.0); +} + }}} //ns diff --git a/modules/gui/src/data_viewer/mask_overlay.hh b/modules/gui/src/data_viewer/mask_overlay.hh index e274f315756060af5001d610e550b42f410a1e83..36feb893d9d0d71893568fab4273c96314636ca0 100644 --- a/modules/gui/src/data_viewer/mask_overlay.hh +++ b/modules/gui/src/data_viewer/mask_overlay.hh @@ -56,6 +56,8 @@ public: void ClearMask(); void ClearShift(){shift_=geom::Vec2();} geom::Vec2 GetShift(){return shift_;} + void SetShift(geom::Vec2 shift); + void ApplyShiftToMask(); protected: std::vector<geom::Polygon2> polygons_; diff --git a/modules/gui/src/file_browser.cc b/modules/gui/src/file_browser.cc index c854be414df655e39e187ae2fa8efd21988dc963..c7919c7ecd28f309fe625a0b19855e90774d383d 100644 --- a/modules/gui/src/file_browser.cc +++ b/modules/gui/src/file_browser.cc @@ -16,12 +16,15 @@ // along with this library; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA //------------------------------------------------------------------------------ +#include <QCursor> #include <QVBoxLayout> +#include <QDesktopServices> #include <QDir> #include <QHeaderView> #include <QFileInfo> #include <QMessageBox> #include <QApplication> +#include <QUrl> #include <ost/platform.hh> #include <ost/config.hh> @@ -91,6 +94,8 @@ void FileBrowser::Init(const QString& path) view_->setModel(model_); view_->setRootIndex(model_->index(path)); view_->setAttribute(Qt::WA_MacShowFocusRect, false); + view_->setContextMenuPolicy(Qt::CustomContextMenu); + connect(view_,SIGNAL(customContextMenuRequested(const QPoint&)),this,SLOT(ShowContextMenu(const QPoint&))); menu_= new QComboBox(this); UpdateMenu(path); @@ -137,13 +142,7 @@ bool FileBrowser::Restore(const QString& prefix) void FileBrowser::DoubleClicked(const QModelIndex& index) { - if(model_->isDir(index)){ - view_->setRootIndex(index); - UpdateMenu(model_->filePath(index)); - } - else{ - LoadObject(index); - } + LoadObject(index); } void FileBrowser::ChangeToParentDirectory(int index){ @@ -193,10 +192,15 @@ void FileBrowser::AddItem(const QDir& directory, const QString& mypath){ } void FileBrowser::LoadObject(const QModelIndex& index){ - gfx::GfxObjP obj; if (index.isValid()) { - QString file_name=model_->filePath(index); - FileLoader::LoadObject(file_name); + if(model_->isDir(index)){ + view_->setRootIndex(index); + UpdateMenu(model_->filePath(index)); + } + else{ + QString file_name=model_->filePath(index); + FileLoader::LoadObject(file_name); + } } } @@ -206,6 +210,43 @@ void FileBrowser::keyPressEvent(QKeyEvent* event){ } } +void FileBrowser::ShowContextMenu(const QPoint& pos){ + + QModelIndex index = view_->selectionModel()->currentIndex(); + QMenu* menu = new QMenu(this); + if(model_->isDir(index)){ + QAction* open_action = new QAction(menu); + open_action->setText("Open"); + connect(open_action,SIGNAL(triggered(bool)),this,SLOT(LoadCurrentObject())); + menu->addAction(open_action); + } + if(!model_->isDir(index)){ + QAction* load_action = new QAction(menu); + load_action->setText("Load"); + connect(load_action,SIGNAL(triggered(bool)),this,SLOT(LoadCurrentObject())); + menu->addAction(load_action); + QAction* system_open_action = new QAction(menu); + system_open_action->setText("Open with system editor"); + connect(system_open_action,SIGNAL(triggered(bool)),this,SLOT(LoadWithSystemEditor())); + menu->addAction(system_open_action); + } + if(menu->actions().size()>0){ + menu->exec(QCursor::pos()); + } +} + +void FileBrowser::LoadCurrentObject(){ + QModelIndex index = view_->selectionModel()->currentIndex(); + this->LoadObject(index); +} + +void FileBrowser::LoadWithSystemEditor(){ + QModelIndex index = view_->selectionModel()->currentIndex(); + QString file_name=model_->filePath(index); + QDesktopServices::openUrl(QUrl::fromLocalFile(file_name)); +} + + OST_REGISTER_WIDGET_WITH_DEFAULT_FACTORY(ost::gui, FileBrowser, "File Browser"); diff --git a/modules/gui/src/file_browser.hh b/modules/gui/src/file_browser.hh index 78ad1acf73a5453febeb092cc01c2a747ed1474c..3f04a0b8e4122c7267c44dfb7700a027e5270be0 100644 --- a/modules/gui/src/file_browser.hh +++ b/modules/gui/src/file_browser.hh @@ -51,6 +51,9 @@ private slots: void DoubleClicked(const QModelIndex& index); void ChangeToParentDirectory(int index); void Split(); + void ShowContextMenu(const QPoint& pos); + void LoadCurrentObject(); + void LoadWithSystemEditor(); private: void LoadObject(const QModelIndex& index); void UpdateMenu(const QString& path); diff --git a/modules/gui/src/file_loader.cc b/modules/gui/src/file_loader.cc index 892278c56393775ea3c93549652fa9f9814ee00d..31636340e150d1ed3c06284165bc2255789aeeb4 100644 --- a/modules/gui/src/file_loader.cc +++ b/modules/gui/src/file_loader.cc @@ -38,6 +38,9 @@ #include <ost/conop/conop.hh> +#include <ost/seq/sequence_list.hh> +#include <ost/seq/alignment_handle.hh> + #include <ost/gfx/entity.hh> #include <ost/gfx/surface.hh> #include <ost/gfx/scene.hh> @@ -47,6 +50,7 @@ #include <ost/gui/python_shell/python_interpreter.hh> #include <ost/gui/main_area.hh> #include <ost/gui/file_type_dialog.hh> +#include <ost/gui/sequence_viewer/sequence_viewer.hh> #if OST_IMG_ENABLED #include <ost/io/img/load_map.hh> @@ -88,11 +92,22 @@ void FileLoader::LoadObject(const QString& filename, const QString& selection) } } #endif + if (!obj) { + try{ + obj=FileLoader::TryLoadAlignment(filename); + } catch (io::IOFileAlreadyLoadedException&) { + return; + } + } if (!obj) { obj=FileLoader::TryLoadSurface(filename); } if (!obj) { - obj=FileLoader::NoHandlerFound(filename); + try{ + obj=FileLoader::NoHandlerFound(filename); + } catch (io::IOFileAlreadyLoadedException&) { + return; + } } if (!obj){ return; @@ -124,6 +139,9 @@ gfx::GfxObjP FileLoader::NoHandlerFound(const QString& filename) if(dialog.GetEntityHandler()){ return TryLoadEntity(filename, dialog.GetEntityHandler()); } + if(dialog.GetSequenceHandler()){ + return TryLoadAlignment(filename, dialog.GetSequenceHandler()); + } if(dialog.GetSurfaceHandler()){ return TryLoadSurface(filename,dialog.GetSurfaceHandler()); } @@ -199,9 +217,15 @@ void FileLoader::HandleError(Message m, ErrorType type, const QString& filename, break; } } + else if(type==INFO){ + QMessageBox message_box(QMessageBox::Information, + "Information", m._mesg.c_str()); + message_box.setStandardButtons( QMessageBox::Ok); + message_box.exec(); + } } -gfx::GfxObjP FileLoader::TryLoadEntity(const QString& filename, io::EntityIOHandlerP handler, const QString& selection) throw (io::IOException) +gfx::GfxObjP FileLoader::TryLoadEntity(const QString& filename, io::EntityIOHandlerP handler, const QString& selection) { if(!handler){ try{ @@ -232,7 +256,7 @@ gfx::GfxObjP FileLoader::TryLoadEntity(const QString& filename, io::EntityIOHand } #if OST_IMG_ENABLED -gfx::GfxObjP FileLoader::TryLoadMap(const QString& filename, io::MapIOHandlerPtr handler) throw(io::IOException, io::IOFileAlreadyLoadedException) +gfx::GfxObjP FileLoader::TryLoadMap(const QString& filename, io::MapIOHandlerPtr handler) { if(!handler){ try{ @@ -266,7 +290,7 @@ gfx::GfxObjP FileLoader::TryLoadMap(const QString& filename, io::MapIOHandlerPtr } #endif -gfx::GfxObjP FileLoader::TryLoadSurface(const QString& filename, io::SurfaceIOHandlerPtr handler) throw(io::IOException) +gfx::GfxObjP FileLoader::TryLoadSurface(const QString& filename, io::SurfaceIOHandlerPtr handler) { if(!handler){ try{ @@ -296,6 +320,29 @@ gfx::GfxObjP FileLoader::TryLoadSurface(const QString& filename, io::SurfaceIOHa return gfx::GfxObjP(); } +gfx::GfxObjP FileLoader::TryLoadAlignment(const QString& filename, io::SequenceIOHandlerPtr handler) +{ + if(!handler){ + try{ + handler = io::IOManager::Instance().FindAlignmentImportHandler(filename.toStdString(),"auto"); + } + catch(io::IOUnknownFormatException e){ + handler = io::SequenceIOHandlerPtr(); + } + } + if(handler){ + seq::SequenceList seq_list = seq::CreateSequenceList(); + handler->Import(seq_list,filename.toStdString()); + seq::AlignmentHandle alignment = seq::AlignmentFromSequenceList(seq_list); + gui::MainArea* main_area = gui::GostyApp::Instance()->GetPerspective()->GetMainArea(); + SequenceViewer* viewer = new SequenceViewer(true,main_area); + viewer->AddAlignment(alignment); + main_area->AddWidget(filename,viewer); + throw io::IOFileAlreadyLoadedException("Loaded in DataViewer"); + } + return gfx::GfxObjP(); +} + void FileLoader::RunScript(const QString& filename) { PythonInterpreter& pi = PythonInterpreter::Instance(); @@ -320,9 +367,11 @@ void FileLoader::LoadPDB(const QString& filename, const QString& selection) conop::Conopology::Instance().ConnectAll(builder,ent,0); entities.append(ent); } - QFileInfo file_info(filename); - if(entities.size()==1){ + if(entities.empty()){ + FileLoader::HandleError(Message(QString("No entities found in file: "+ filename).toStdString()),INFO,filename); + } + else if(entities.size()==1){ gfx::EntityP gfx_ent(new gfx::Entity(file_info.baseName().toStdString(),entities.first(),mol::Query(selection.toStdString()))); try{ gfx::Scene::Instance().Add(gfx_ent); diff --git a/modules/gui/src/file_loader.hh b/modules/gui/src/file_loader.hh index b102e17f69e0a62df75e1078c64dd79459b277a9..ea2d63e2d8e04eba39eddbff64dae637438fe77c 100644 --- a/modules/gui/src/file_loader.hh +++ b/modules/gui/src/file_loader.hh @@ -32,6 +32,7 @@ #include <ost/io/io_exception.hh> #include <ost/io/entity_io_handler.hh> +#include <ost/io/sequence_io_handler.hh> #include <ost/io/surface_io_handler.hh> #if OST_IMG_ENABLED #include <ost/io/map_io_handler.hh> @@ -45,14 +46,16 @@ private: enum ErrorType { DEFAULT = 0, IO_LOADING, GFX_ADD, - GFX_MULTIPLE_ADD + GFX_MULTIPLE_ADD, + INFO }; FileLoader(); - static gfx::GfxObjP TryLoadEntity(const QString& filename, io::EntityIOHandlerP handler=io::EntityIOHandlerP(), const QString& selection=QString()) throw (io::IOException); - static gfx::GfxObjP TryLoadSurface(const QString& filename, io::SurfaceIOHandlerPtr handler=io::SurfaceIOHandlerPtr()) throw (io::IOException); + static gfx::GfxObjP TryLoadEntity(const QString& filename, io::EntityIOHandlerP handler=io::EntityIOHandlerP(), const QString& selection=QString()); + static gfx::GfxObjP TryLoadSurface(const QString& filename, io::SurfaceIOHandlerPtr handler=io::SurfaceIOHandlerPtr()); + static gfx::GfxObjP TryLoadAlignment(const QString& filename, io::SequenceIOHandlerPtr handler=io::SequenceIOHandlerPtr()); #if OST_IMG_ENABLED - static gfx::GfxObjP TryLoadMap(const QString& filename, io::MapIOHandlerPtr handler=io::MapIOHandlerPtr()) throw (io::IOException, io::IOFileAlreadyLoadedException); + static gfx::GfxObjP TryLoadMap(const QString& filename, io::MapIOHandlerPtr handler=io::MapIOHandlerPtr()); #endif static void RunScript(const QString& filename); static void LoadPDB(const QString& filename, const QString& selection=QString()); diff --git a/modules/gui/src/file_type_dialog.cc b/modules/gui/src/file_type_dialog.cc index cba2cba951411a1347fc962bda008fae828dbccf..ac9dd54ab797b3114ac7ab27d4cf409488f8108a 100644 --- a/modules/gui/src/file_type_dialog.cc +++ b/modules/gui/src/file_type_dialog.cc @@ -30,7 +30,7 @@ namespace ost { namespace gui { FileTypeDialog::FileTypeDialog(const QString& file_name, QWidget* parent): - QDialog(parent),entity_handler_(), surf_handler_() + QDialog(parent),entity_handler_(),seq_handler_(), surf_handler_() #if OST_IMG_ENABLED ,map_handler_() #endif @@ -66,6 +66,13 @@ FileTypeDialog::FileTypeDialog(const QString& file_name, QWidget* parent): this->AddRow(list_->rowCount(),entity_handler[i]->GetFormatName().c_str(),entity_handler[i]->GetFormatDescription().c_str(),handler); } + io::AlignmentIOFList alignment_handler = io::IOManager::Instance().GetAvailableAlignmentHandler(); + for(unsigned int i = 0 ; i < alignment_handler.size() ; i++){ + QVariant handler = QVariant(); + handler.setValue(alignment_handler[i]); + this->AddRow(list_->rowCount(),alignment_handler[i]->GetFormatName().c_str(),alignment_handler[i]->GetFormatDescription().c_str(),handler); + } + #if OST_IMG_ENABLED io::MapIOFList map_handler = io::IOManager::Instance().GetAvailableMapHandler(); for(unsigned int i = 0 ; i < map_handler.size() ; i++){ @@ -106,6 +113,11 @@ void FileTypeDialog::accept(){ entity_handler_ = ent_handler_fac->Create(); break; } + io::SequenceIOHandlerFactoryBasePtr seq_handler_fac = variant.value<io::SequenceIOHandlerFactoryBasePtr>(); + if(seq_handler_fac){ + seq_handler_ = seq_handler_fac->Create(); + break; + } io::SurfaceIOHandlerFactoryBasePtr surf_handler_fac = variant.value<io::SurfaceIOHandlerFactoryBasePtr>(); if(surf_handler_fac){ surf_handler_ = surf_handler_fac->Create(); @@ -127,6 +139,9 @@ io::EntityIOHandlerP FileTypeDialog::GetEntityHandler(){ return entity_handler_; } +io::SequenceIOHandlerPtr FileTypeDialog::GetSequenceHandler(){ + return seq_handler_; +} io::SurfaceIOHandlerPtr FileTypeDialog::GetSurfaceHandler(){ return surf_handler_; diff --git a/modules/gui/src/file_type_dialog.hh b/modules/gui/src/file_type_dialog.hh index 3efee2c535739d0c2e068600a25cd5a9da49e388..b0d6e44338a655ab80d08b4ffd3b8568cc498f20 100644 --- a/modules/gui/src/file_type_dialog.hh +++ b/modules/gui/src/file_type_dialog.hh @@ -31,6 +31,7 @@ #include <QLabel> #include <ost/io/entity_io_handler.hh> +#include <ost/io/sequence_io_handler.hh> #include <ost/io/surface_io_handler.hh> #if OST_IMG_ENABLED #include <ost/io/map_io_handler.hh> @@ -44,6 +45,7 @@ class DLLEXPORT_OST_GUI FileTypeDialog : public QDialog { public: FileTypeDialog(const QString& file_name, QWidget* parent=NULL); io::EntityIOHandlerP GetEntityHandler(); + io::SequenceIOHandlerPtr GetSequenceHandler(); io::SurfaceIOHandlerPtr GetSurfaceHandler(); #if OST_IMG_ENABLED io::MapIOHandlerPtr GetMapHandler(); @@ -59,6 +61,7 @@ private: QTableWidget* list_; QLabel* label_; io::EntityIOHandlerP entity_handler_; + io::SequenceIOHandlerPtr seq_handler_; io::SurfaceIOHandlerPtr surf_handler_; #if OST_IMG_ENABLED io::MapIOHandlerPtr map_handler_; @@ -69,6 +72,7 @@ private: }} Q_DECLARE_METATYPE(ost::io::EntityIOHandlerFactoryBaseP); +Q_DECLARE_METATYPE(ost::io::SequenceIOHandlerFactoryBasePtr); Q_DECLARE_METATYPE(ost::io::SurfaceIOHandlerFactoryBasePtr); #if OST_IMG_ENABLED Q_DECLARE_METATYPE(ost::io::MapIOHandlerFactoryBasePtr); diff --git a/modules/gui/src/gosty_app.cc b/modules/gui/src/gosty_app.cc index b78c4f79466b7bd346b379a685bb34f598e8efef..7090e7449d5ad5948e6c3361547560947d39a30b 100644 --- a/modules/gui/src/gosty_app.cc +++ b/modules/gui/src/gosty_app.cc @@ -46,7 +46,7 @@ GostyApp* GostyApp::app_=NULL; GostyApp::GostyApp(): py_shell_(NULL), w_py_shell_(NULL), gl_win_(NULL), w_gl_win_(NULL), - scene_win_(NULL), w_scene_win_(NULL), seq_viewer_(NULL), seq_viewer_v2_(NULL), tool_options_win_(NULL), + scene_win_(NULL), w_scene_win_(NULL), seq_viewer_(NULL), tool_options_win_(NULL), w_tool_options_(NULL), main_(new GostyMainWindow), perspective_(NULL), external_widgets_(QMap<QString,WidgetGeomHandler *>()) { @@ -98,21 +98,12 @@ SceneWin* GostyApp::GetSceneWin() SequenceViewer* GostyApp::GetSequenceViewer() { if (seq_viewer_==NULL) { - seq_viewer_=new SequenceViewer; - seq_viewer_->SetDestroyOnClose(false); + seq_viewer_=new SequenceViewer(false); + seq_viewer_->SetDestroyOnClose(false); } return seq_viewer_; } -SequenceViewerV2* GostyApp::GetSequenceViewerV2() -{ - if (seq_viewer_v2_==NULL) { - seq_viewer_v2_=new SequenceViewerV2; - seq_viewer_v2_->SetDestroyOnClose(false); - } - return seq_viewer_v2_; -} - #if OST_IMG_ENABLED ost::img::gui::DataViewer* GostyApp::CreateDataViewer(const ost::img::Data& d, const QString& name) { diff --git a/modules/gui/src/gosty_app.hh b/modules/gui/src/gosty_app.hh index 46381ff1662237a5b60525407d7936eb05bd3eb4..f9ce1d851526513ed93f8d825ffc8a3ab74ca600 100644 --- a/modules/gui/src/gosty_app.hh +++ b/modules/gui/src/gosty_app.hh @@ -31,7 +31,6 @@ #include <ost/gui/module_config.hh> #include <ost/gui/scene_win/scene_win.hh> #include <ost/gui/sequence_viewer/sequence_viewer.hh> -#include <ost/gui/sequence/sequence_viewer.hh> #include <ost/gui/main.hh> #include <ost/gui/widget_geom_handler.hh> #if OST_IMG_ENABLED @@ -93,7 +92,6 @@ public: /// The sequence viewer is initialized when this method is first called. All /// subsequent calls will return the same SequenceViewer instance. SequenceViewer* GetSequenceViewer(); - SequenceViewerV2* GetSequenceViewerV2(); /// \brief get tool options window /// @@ -156,8 +154,7 @@ private: SceneWin* scene_win_; QWidget* w_scene_win_; - SequenceViewer* seq_viewer_; - SequenceViewerV2* seq_viewer_v2_; + SequenceViewer* seq_viewer_; ToolOptionsWin* tool_options_win_; QWidget* w_tool_options_; diff --git a/modules/gui/src/main.cc b/modules/gui/src/main.cc index 9836c6e9057805a340c8559ee51183e08232581d..9abeac746c3a53ed5d99ea631814997db97e2ced 100644 --- a/modules/gui/src/main.cc +++ b/modules/gui/src/main.cc @@ -43,7 +43,6 @@ #include "gl_win.hh" //#include "entity_explorer/entity_explorer.hh" #include "mdi_sub_window.hh" -#include "sequence_viewer/sequence_viewer.hh" #include "tools/tool_options_win.hh" #include "plot_viewer/plot_viewer_proxy.hh" #include "plot_viewer/plot_viewer.hh" diff --git a/modules/gui/src/plot_viewer/plot_viewer_panel.cc b/modules/gui/src/plot_viewer/plot_viewer_panel.cc index 07ec70d9dda3ca887cc44b8c51309c6aa79ce01f..a440c06803b475b0d90dd3ac2ebf1151ecdf4074 100644 --- a/modules/gui/src/plot_viewer/plot_viewer_panel.cc +++ b/modules/gui/src/plot_viewer/plot_viewer_panel.cc @@ -138,7 +138,7 @@ void PlotViewerPanel::wheelEvent ( QWheelEvent * e ) } void PlotViewerPanel::OnZoomX(int delta,QPoint pos) { - QPointF cursorpos=mapToScene(pos+QPoint(-PlotAxisBase::AXISWIDTH,0)); + QPointF cursorpos=mapToScene(pos+QPoint(-int(PlotAxisBase::AXISWIDTH),0)); Real scalefactor=exp(delta/1000.0); QRectF scenerect; scenerect.setCoords(cursorpos.x()-(cursorpos.x()-GetMinimumX())/scalefactor, diff --git a/modules/gui/src/python_shell/dir_model.cc b/modules/gui/src/python_shell/dir_model.cc index 96c57f61a1c308829fd1f8440a0509d86afd751a..e4d2c049bce398096108d46db00bec0da1ac3579 100644 --- a/modules/gui/src/python_shell/dir_model.cc +++ b/modules/gui/src/python_shell/dir_model.cc @@ -20,7 +20,6 @@ Author: Andreas Schenk */ - #include "dir_model.hh" diff --git a/modules/gui/src/scene_selection.cc b/modules/gui/src/scene_selection.cc index eb92c848e96f0279c5e526e71887297d16ea9dc5..7beeadc58d7777ca7362424ca03692902d628657 100644 --- a/modules/gui/src/scene_selection.cc +++ b/modules/gui/src/scene_selection.cc @@ -152,6 +152,23 @@ void SceneSelection::ViewDensitySlices() { } } +void SceneSelection::ShowDownsampledMap() +{ + gfx::MapIsoP obj = dyn_cast<gfx::MapIso> (nodes_[0]); + if (obj) { + obj->ShowDownsampledMap(); + } +} + + +void SceneSelection::ShowOriginalMap() +{ + gfx::MapIsoP obj = dyn_cast<gfx::MapIso> (nodes_[0]); + if (obj) { + obj->ShowOriginalMap(); + } +} + #endif // OST_IMG_ENABLED void SceneSelection::Select() { diff --git a/modules/gui/src/scene_selection.hh b/modules/gui/src/scene_selection.hh index 3b5bebabb3aaaca1bccab963d0bd371cf62c446c..7bbcb2e38416152138f1cd48b2f817ff98174855 100644 --- a/modules/gui/src/scene_selection.hh +++ b/modules/gui/src/scene_selection.hh @@ -46,6 +46,8 @@ public slots: void Delete(); #if OST_IMG_ENABLED void ViewDensitySlices(); + void ShowDownsampledMap(); + void ShowOriginalMap(); #endif // OST_IMG_ENABLED void CopyViews(); void Select(); @@ -61,6 +63,7 @@ public slots: void HideExclusive(); mol::EntityView GetViewUnion(); + private slots: void SetActiveNodes(gfx::NodePtrList nodes, gfx::EntityP entity, mol::QueryViewWrapperList views); diff --git a/modules/gui/src/scene_win/context_menu.cc b/modules/gui/src/scene_win/context_menu.cc index d873c99f5ba58e3ed84404a49e177821bd3ce570..afce21203c2508af289a1034a0e6685e4db1c6cc 100644 --- a/modules/gui/src/scene_win/context_menu.cc +++ b/modules/gui/src/scene_win/context_menu.cc @@ -26,6 +26,8 @@ #include <QItemSelection> #include <QItemSelectionModel> +#include <ost/dyn_cast.hh> + #include <ost/gui/scene_selection.hh> #include <ost/gui/query_dialog.hh> @@ -114,6 +116,14 @@ ContextMenu::ContextMenu(QTreeView* view, SceneWinModel* model): action = new QAction("View Density Slices",this); connect(action, SIGNAL(triggered()), SceneSelection::Instance(), SLOT(ViewDensitySlices())); this->AddAction(action, MAP); + + action = new QAction("Show Original Map",this); + connect(action, SIGNAL(triggered()), SceneSelection::Instance(), SLOT(ShowOriginalMap())); + this->AddAction(action, MAP | SINGLE | MAP_DOWNSAMPLED); + + action = new QAction("Show Downsampled Map",this); + connect(action, SIGNAL(triggered()), SceneSelection::Instance(), SLOT(ShowDownsampledMap())); + this->AddAction(action, MAP | SINGLE | MAP_ORIGINAL | MAP_DSAMPLED_AVAIL); #endif // OST_IMG_ENABLED } @@ -139,10 +149,28 @@ void ContextMenu::ShowMenu(const QPoint& pos) flags &= ~NOT_VISIBLE; } if(gfx_node->GetType()==0){flags &= ~NOT_SCENE;} - if(!dynamic_cast<gfx::GfxObj*> (gfx_node.get())){flags &= ~GFX_OBJECT;} - if(!dynamic_cast<gfx::Entity*> (gfx_node.get())){flags &= ~ENTITY;} + if(!dyn_cast<gfx::GfxObj> (gfx_node)){flags &= ~GFX_OBJECT;} + if(!dyn_cast<gfx::Entity> (gfx_node)){flags &= ~ENTITY;} #if OST_IMG_ENABLED - if(!dynamic_cast<gfx::MapIso*> (gfx_node.get())){flags &= ~MAP;} + if(!dyn_cast<gfx::MapIso>(gfx_node)) + { + flags &= ~MAP; + } else { + gfx::MapIsoP mapisop = dyn_cast<gfx::MapIso> (gfx_node); + if (mapisop->GetShownMapType() == gfx::ORIGINAL_MAP){ + flags &= ~MAP_DOWNSAMPLED; + } else { + flags &= ~MAP_ORIGINAL; + } + if (mapisop->IsDownsampledMapAvailable() == false){ + flags &= ~MAP_DSAMPLED_AVAIL; + } + } + if(!dyn_cast<gfx::MapIso> (gfx_node)){ + flags &= ~MAP; + + } + if(!dyn_cast<gfx::MapIso> (gfx_node)){flags &= ~MAP;} #endif // OST_IMG_ENABLED } else{ diff --git a/modules/gui/src/scene_win/context_menu.hh b/modules/gui/src/scene_win/context_menu.hh index bc2f8e9d133215c7c66550e4b68c31e2ad575b77..1a2501da86e6f7fea9cc09b56b0cd00b67a4f893 100644 --- a/modules/gui/src/scene_win/context_menu.hh +++ b/modules/gui/src/scene_win/context_menu.hh @@ -45,7 +45,10 @@ enum ContextActionType SINGLE=0x80, MULTI=0x100 #if OST_IMG_ENABLED - ,MAP=0x200 + ,MAP=0x200, + MAP_ORIGINAL=0x400, + MAP_DOWNSAMPLED=0x800, + MAP_DSAMPLED_AVAIL=0x1000 #endif }; Q_DECLARE_FLAGS(ContextActionTypes, ContextActionType) diff --git a/modules/gui/src/scene_win/gfx_scene_node.cc b/modules/gui/src/scene_win/gfx_scene_node.cc index 9b8828779f3a85f3e20c726276fe608e64bffdf1..f8632e9018d3933e0df87ac2d5e61adcd02d3575 100644 --- a/modules/gui/src/scene_win/gfx_scene_node.cc +++ b/modules/gui/src/scene_win/gfx_scene_node.cc @@ -71,10 +71,10 @@ bool GfxSceneNode::SetData(int column, const QVariant& value, int role){ Qt::ItemFlags GfxSceneNode::Flags(int column) const{ if(column==0){ - return Qt::ItemIsSelectable|Qt::ItemIsUserCheckable|Qt::ItemIsEnabled; + return Qt::ItemIsSelectable|Qt::ItemIsUserCheckable|Qt::ItemIsEnabled|Qt::ItemIsDragEnabled; } else if(column==1){ - return Qt::ItemIsSelectable|Qt::ItemIsEnabled|Qt::ItemIsEditable; + return Qt::ItemIsSelectable|Qt::ItemIsEnabled|Qt::ItemIsEditable|Qt::ItemIsDragEnabled; } return Qt::NoItemFlags; } diff --git a/modules/gui/src/scene_win/render_mode_node.cc b/modules/gui/src/scene_win/render_mode_node.cc index 63789cd3748647cf9b595cc57c2a2826e48defe1..52836c04362844e8689f28ba3d18d91cfd1f6ce5 100644 --- a/modules/gui/src/scene_win/render_mode_node.cc +++ b/modules/gui/src/scene_win/render_mode_node.cc @@ -77,9 +77,9 @@ gfx::RenderMode::Type RenderModeNode::GetRenderMode() const { return render_mode_; } -void RenderModeNode::SetQueryView(mol::QueryViewWrapper part) +void RenderModeNode::Update() { - //Do Nothing + this->SetQueryView(mol::QueryViewWrapper(entity_->GetRenderView(this->GetRenderMode()))); } }} diff --git a/modules/gui/src/scene_win/render_mode_node.hh b/modules/gui/src/scene_win/render_mode_node.hh index 68bf5300ee720a5becd74a2e0b07e890d4801d68..f5de2d0842fe62a6052518409fcd06a3e63458b6 100644 --- a/modules/gui/src/scene_win/render_mode_node.hh +++ b/modules/gui/src/scene_win/render_mode_node.hh @@ -54,8 +54,7 @@ public: gfx::RenderMode::Type GetRenderMode() const; - virtual void SetQueryView(mol::QueryViewWrapper part); - + virtual void Update(); private: gfx::EntityP entity_; gfx::RenderMode::Type render_mode_; diff --git a/modules/gui/src/scene_win/render_modes_node.cc b/modules/gui/src/scene_win/render_modes_node.cc index 0e46a1a03ea6ef71b9d8a1f2d352cf0542547071..4c551f6b79b0eb5f649a03adb9eb0727693ced7d 100644 --- a/modules/gui/src/scene_win/render_modes_node.cc +++ b/modules/gui/src/scene_win/render_modes_node.cc @@ -54,6 +54,9 @@ void RenderModesNode::Update(){ model->AddNode(this, node); render_types_.insert(render_modes[i],node); } + else{ + render_types_[render_modes[i]]->Update(); + } } QSet<gfx::RenderMode::Type> types_to_delete; QMap<gfx::RenderMode::Type,RenderModeNode*>::iterator type; diff --git a/modules/gui/src/scene_win/scene_win.cc b/modules/gui/src/scene_win/scene_win.cc index 213582ff632aa1e697fbd193e528a1caccfbf7b3..0b2e75bd3bea9df0f7ddbfda13550b5601c685bf 100644 --- a/modules/gui/src/scene_win/scene_win.cc +++ b/modules/gui/src/scene_win/scene_win.cc @@ -52,12 +52,14 @@ SceneWin::SceneWin(QWidget* parent) : view_ = new QTreeView(this); context_menu_ = new ContextMenu(view_,model_); view_->setAttribute(Qt::WA_MacShowFocusRect, false); + view_->setAttribute(Qt::WA_MacSmallSize, true); view_->header()->hide(); view_->setContextMenuPolicy(Qt::CustomContextMenu); view_->setModel(model_); view_->setSelectionBehavior(QAbstractItemView::SelectRows); view_->setSelectionMode(QAbstractItemView::ExtendedSelection); view_->setEditTriggers(QAbstractItemView::EditKeyPressed); + view_->setDragEnabled(true); view_->expandAll(); layout->addWidget(view_); diff --git a/modules/gui/src/scene_win/scene_win_model.cc b/modules/gui/src/scene_win/scene_win_model.cc index 12df1534d79e3ac9ed4d2dc609773a1cb88ad8e8..9e7542b0815c2a73267820ad1fa1b1991cf8cce9 100644 --- a/modules/gui/src/scene_win/scene_win_model.cc +++ b/modules/gui/src/scene_win/scene_win_model.cc @@ -198,6 +198,36 @@ bool SceneWinModel::setData(const QModelIndex& index, return false; } +QStringList SceneWinModel::mimeTypes() const +{ + QStringList types; + types << "text/plain"; + return types; +} + +Qt::DropActions SceneWinModel::supportedDragActions() const +{ + return Qt::MoveAction; +} + +QMimeData* SceneWinModel::mimeData(const QModelIndexList &indexes) const +{ + QMimeData *mimeData = new QMimeData(); + QByteArray encoded_data; + + QDataStream stream(&encoded_data, QIODevice::WriteOnly); + + + foreach (QModelIndex index, indexes) { + if (index.isValid() && index.column()==1) { + QString text = "scene['"+data(index, Qt::DisplayRole).toString()+"']"; + encoded_data.append(text); + } + } + mimeData->setData("text/plain", encoded_data); + return mimeData; +} + void SceneWinModel::NodeAdded(const gfx::GfxNodeP& node) { gfx::EntityP e=boost::dynamic_pointer_cast<gfx::Entity>(node); diff --git a/modules/gui/src/scene_win/scene_win_model.hh b/modules/gui/src/scene_win/scene_win_model.hh index 996f7b640de20d1e9fea7303a7f162649757524c..c65af6677974af714ad602a61b1d8b9498391a20 100644 --- a/modules/gui/src/scene_win/scene_win_model.hh +++ b/modules/gui/src/scene_win/scene_win_model.hh @@ -23,6 +23,8 @@ Author: Stefan Scheuber, Marco Biasini, Ansgar Philippsen */ +#include <QStringList> +#include <QMimeData> #include <QMap> #include <QAbstractItemModel> @@ -88,6 +90,10 @@ public: const QVariant& value=QVariant(), int role=Qt::DisplayRole); + virtual QStringList mimeTypes() const; + Qt::DropActions supportedDragActions() const; + virtual QMimeData* mimeData(const QModelIndexList& indexes) const; + // scene observer interface virtual void NodeAdded(const gfx::GfxNodeP& node); virtual void NodeRemoved(const gfx::GfxNodeP& node); diff --git a/modules/gui/src/sequence/sequence_model.cc b/modules/gui/src/sequence/sequence_model.cc deleted file mode 100644 index 428952657b2f0bb3e14277fdd2a5dbc4c2cf104c..0000000000000000000000000000000000000000 --- a/modules/gui/src/sequence/sequence_model.cc +++ /dev/null @@ -1,265 +0,0 @@ -//------------------------------------------------------------------------------ -// This file is part of the OpenStructure project <www.openstructure.org> -// -// Copyright (C) 2008-2010 by the OpenStructure authors -// -// This library is free software; you can redistribute it and/or modify it under -// the terms of the GNU Lesser General Public License as published by the Free -// Software Foundation; either version 3.0 of the License, or (at your option) -// any later version. -// This library is distributed in the hope that it will be useful, but WITHOUT -// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -// details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this library; if not, write to the Free Software Foundation, Inc., -// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -//------------------------------------------------------------------------------ - -/* - Author: Stefan Scheuber - */ - -#include <QMap> -#include <QMapIterator> - -#include <QtGui> - -#include "sequence_model.hh" - -namespace ost { namespace gui { - -SequenceModel::SequenceModel(QObject *parent) - : QAbstractTableModel(parent), max_columns(0) -{ - this->beginInsertRows(QModelIndex(),this->rowCount(),this->rowCount()); - objects_.append(new ViewObject(this)); - this->endInsertRows(); -} - -void SequenceModel::InsertSequence(QString& name, seq::SequenceHandle& seq){ - int cols = this->columnCount(); - int new_cols = seq.GetLength(); - this->beginInsertRows(QModelIndex(),this->rowCount(),this->rowCount()); - objects_.append(new ViewObject(seq, name, this)); - if(new_cols > cols){ - this->max_columns = new_cols; - this->beginInsertColumns(QModelIndex(), cols, new_cols); - this->endInsertColumns(); - } - this->endInsertRows(); -} - -void SequenceModel::InsertChain(QString& name, mol::ChainView& view){ - int cols = this->columnCount(); - int new_cols = view.GetResidueCount(); - this->beginInsertRows(QModelIndex(),this->rowCount(),this->rowCount()); - objects_.append(new ViewObject(view, name, this)); - if(new_cols > cols){ - this->max_columns = new_cols; - this->beginInsertColumns(QModelIndex(), cols, new_cols); - this->endInsertColumns(); - } - this->endInsertRows(); -} - -void SequenceModel::InsertSequences(const QList<QString>& names, seq::SequenceList& list){ - this->beginInsertRows(this->index(this->rowCount(),0),this->rowCount(),this->rowCount()+list.GetCount()); - objects_.append(new ViewObject(list, names, this)); - this->endInsertRows(); -} - -void SequenceModel::InsertGfxEntity(gfx::EntityP& ent){ - mol::EntityView view=ent->GetView(); - int size = view.GetChainList().size(); - int cols = this->columnCount(); - this->beginInsertRows(QModelIndex(),this->rowCount(),this->rowCount()+size); - ViewObject* obj = new ViewObject(ent, this); - objects_.append(obj); - int new_cols = obj->GetMaxColumnCount(); - if(new_cols > cols){ - this->max_columns = new_cols; - this->beginInsertColumns(QModelIndex(), cols, new_cols); - this->endInsertColumns(); - } - this->endInsertRows(); -} - -void SequenceModel::RemoveGfxEntity(gfx::EntityP& entity){ - if(ViewObject* obj = this->GetItem(entity)){ - int index = this->GetGlobalRow(obj,0); - this->beginRemoveRows(QModelIndex(),index,index+obj->GetRowCount()-1); - int cols_before = this->columnCount(); - objects_.removeOne(obj); - this->endRemoveRows(); - int cols = this->columnCount(); - if(cols_before>cols){ - this->max_columns = cols; - this->beginRemoveColumns(QModelIndex(), cols, cols_before); - this->endRemoveColumns(); - } - } -} - -ViewObject* SequenceModel::GetItem(gfx::EntityP& entity){ - if(entity != NULL){ - for (int i = 0 ; i< objects_.size(); i++){ - if(entity == objects_[i]->GetGfxObject()){ - return objects_[i]; - } - } - } - return NULL; -} - -const PainterList& SequenceModel::GetPainters(const QModelIndex& index) const{ - QPair<int, ViewObject*> pair = this->GetRowWithItem(index); - if(pair.second){ - pair.second->GetRow(pair.first); - return pair.second->GetRow(pair.first)->GetPainters(); - } - assert(false); -} - -QPair<int, ViewObject*> SequenceModel::GetRowWithItem(int row) const{ - if(!objects_.isEmpty()){ - int rows = 0; - int i = -1; - int last_row = 0; - while (rows <= row && i < objects_.size()){ - i++; - last_row =objects_[i]->GetRowCount(); - rows += last_row; - } - int sub_index = row - (rows-last_row); - return QPair<int, ViewObject*>(sub_index, objects_[i]); - } - return QPair<int, ViewObject*>(-1, NULL); -} - -QPair<int, ViewObject*> SequenceModel::GetRowWithItem(const QModelIndex& index) const{ - return this->GetRowWithItem(index.row()); -} - -ViewObject* SequenceModel::GetItem(const QModelIndex& index) const -{ - return this->GetRowWithItem(index).second; -} - -int SequenceModel::GetGlobalRow(ViewObject* obj, int row) const -{ - int glob_row = -1; - int index = objects_.indexOf(obj); - if(index >= 0){ - glob_row = 0; - for(int i=0; i<index; i++){ - glob_row += objects_[i]->GetRowCount(); - } - return glob_row + row; - } - return glob_row; -} - -QModelIndexList SequenceModel::GetModelIndexes(gfx::EntityP& entity, const mol::EntityView& view) -{ - QModelIndexList list; - if(ViewObject* object = this->GetItem(entity)){ - QMap<int, QList<int> > indexes = object->GetIndexesForView(view); - QMapIterator< int, QList<int> > i(indexes); - while (i.hasNext()) { - i.next(); - int row = this->GetGlobalRow(object, i.key()); - const QList<int>& index_list = i.value(); - for(int i=0; i<index_list.size(); i++){ - list.append(this->index(row,index_list[i])); - } - } - } - return list; -} - -void SequenceModel::SelectionChanged(const QItemSelection& sel, const QItemSelection& desel) -{ - QMap<int,QPair<QSet<int>,QSet<int> > > sel_map; - const QModelIndexList& sel_indexes = sel.indexes(); - for(int i =0; i< sel_indexes.size(); i++){ - sel_map[sel_indexes[i].row()].first.insert(sel_indexes[i].column()); - } - - const QModelIndexList& desel_indexes = desel.indexes(); - for(int i =0; i< desel_indexes.size(); i++){ - sel_map[desel_indexes[i].row()].second.insert(desel_indexes[i].column()); - } - - QMapIterator< int,QPair<QSet<int>,QSet<int> > > i(sel_map); - while (i.hasNext()) { - i.next(); - QPair<int, ViewObject*> item = this->GetRowWithItem(i.key()); - item.second->SetSelection(item.first,i.value().first, i.value().second); - } -} - -void SequenceModel::DoubleClicked(const QModelIndex& index) -{ - QPair<int, ViewObject*> item = this->GetRowWithItem(index); - if(item.second){ - item.second->DoubleClicked(item.first,index.column()); - } -} - -int SequenceModel::rowCount(const QModelIndex& parent) const -{ - int rows = 0; - for (int i = 0; i<objects_.size(); i++){ - rows += objects_[i]->GetRowCount(); - } - return rows; -} - -int SequenceModel::columnCount(const QModelIndex& parent) const -{ - return max_columns; -} - -QVariant SequenceModel::data(const QModelIndex& index, int role) const -{ - QPair<int, ViewObject*> item = this->GetRowWithItem(index); - if(!item.second) return QVariant(); - QVariant data = item.second->GetData(item.first,index.column(),role); - return data; -} - -QVariant SequenceModel::headerData(int section, Qt::Orientation orientation, - int role) const -{ - if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { - return QVariant(""); - } - return QVariant(); -} - -Qt::ItemFlags SequenceModel::flags(const QModelIndex& index) const -{ - QPair<int, ViewObject*> item = GetRowWithItem(index); - if(item.second){ - return item.second->Flags(item.first, index.column()); - } - return QAbstractItemModel::flags(index); -} - -void SequenceModel::ZoomIn() -{ - for (int i = 0; i<objects_.size(); i++){ - objects_[i]->ZoomIn(); - } -} - -void SequenceModel::ZoomOut() -{ - for (int i = 0; i<objects_.size(); i++){ - objects_[i]->ZoomOut(); - } -} - -}} diff --git a/modules/gui/src/sequence/sequence_viewer.cc b/modules/gui/src/sequence/sequence_viewer.cc deleted file mode 100644 index fd6a3cf2bcecfcb040758d1f80bb1b624f71b4c6..0000000000000000000000000000000000000000 --- a/modules/gui/src/sequence/sequence_viewer.cc +++ /dev/null @@ -1,179 +0,0 @@ -//------------------------------------------------------------------------------ -// This file is part of the OpenStructure project <www.openstructure.org> -// -// Copyright (C) 2008-2010 by the OpenStructure authors -// -// This library is free software; you can redistribute it and/or modify it under -// the terms of the GNU Lesser General Public License as published by the Free -// Software Foundation; either version 3.0 of the License, or (at your option) -// any later version. -// This library is distributed in the hope that it will be useful, but WITHOUT -// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -// details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this library; if not, write to the Free Software Foundation, Inc., -// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -//------------------------------------------------------------------------------ - -/* - Author: Stefan Scheuber - */ -#include <boost/pointer_cast.hpp> - -#include <QVBoxLayout> -#include <QPushButton> -#include <QHeaderView> -#include <QAbstractItemView> - -#include <ost/mol/chain_view.hh> -#include <ost/mol/entity_view.hh> - -#include <ost/seq/sequence_handle.hh> - -#include <ost/gfx/entity.hh> -#include <ost/gfx/scene.hh> -#include <ost/gfx/gfx_node_visitor.hh> - -#include <ost/gui/widget_registry.hh> -#include <ost/gui/gosty_app.hh> - -#include "sequence_model.hh" -#include "sequence_viewer.hh" - -namespace ost { namespace gui { - -class SequenceViewerV2Factory: public WidgetFactory { -public: - SequenceViewerV2Factory() : - WidgetFactory("ost::gui::SequenceViewerV2", "Sequence Viewer V2") { - } - - virtual Widget* Create(QWidget* parent) { - return GostyApp::Instance()->GetSequenceViewerV2(); - } -}; - -OST_REGISTER_WIDGET(SequenceViewerV2, SequenceViewerV2Factory); - -struct GetNodesVisitor: public gfx::GfxNodeVisitor { - GetNodesVisitor(): nodes_() {} - virtual void VisitObject(gfx::GfxObj* o, const Stack& st) { - nodes_.push_back(o->shared_from_this()); - } - gfx::NodePtrList nodes_; - gfx::NodePtrList GetNodes(){return nodes_;} -}; - -SequenceViewerV2::SequenceViewerV2(QWidget* parent): Widget(NULL,parent) -{ - gfx::Scene::Instance().AttachObserver(this); - model_ = new SequenceModel(this); - - QVBoxLayout* layout = new QVBoxLayout(this); - layout->setMargin(0); - layout->setSpacing(0); - - seq_table_view_ = new SequenceTableView(model_); - layout->addWidget(seq_table_view_); - this->setLayout(layout); - connect(model_,SIGNAL(columnsInserted(const QModelIndex&, int, int)),seq_table_view_,SLOT(columnCountChanged(const QModelIndex&, int, int))); - connect(model_,SIGNAL(rowsInserted(const QModelIndex&, int, int)),seq_table_view_,SLOT(rowCountChanged(const QModelIndex&, int, int))); - - seq_table_view_->horizontalHeader()->setMinimumSectionSize(2); - seq_table_view_->verticalHeader()->setMinimumSectionSize(2); - seq_table_view_->setSelectionMode(QAbstractItemView::ExtendedSelection); - connect(seq_table_view_->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), this, SLOT(SelectionModelChanged(const QItemSelection&, const QItemSelection&))); - connect(seq_table_view_,SIGNAL(doubleClicked(const QModelIndex&)),model_,SLOT(DoubleClicked(const QModelIndex&))); - connect(seq_table_view_->GetStaticColumn(),SIGNAL(doubleClicked(const QModelIndex&)),this,SLOT(DoubleClicked(const QModelIndex&))); - connect(seq_table_view_->GetStaticRow(),SIGNAL(doubleClicked(const QModelIndex&)),this,SLOT(DoubleClicked(const QModelIndex&))); - connect(seq_table_view_,SIGNAL(MouseWheelEvent(QWheelEvent*)),this,SLOT(MouseWheelEvent(QWheelEvent*))); - - gfx::GfxNodeP root_node = gfx::Scene::Instance().GetRootNode(); - GetNodesVisitor gnv; - gfx::Scene::Instance().Apply(gnv); - gfx::NodePtrList list = gnv.GetNodes(); - for(unsigned int i=0; i<list.size();i++){ - this->NodeAdded(list[i]); - } -} - -void SequenceViewerV2::NodeAdded(const gfx::GfxNodeP& n) -{ - if (gfx::EntityP o=boost::dynamic_pointer_cast<gfx::Entity>(n)) { - model_->InsertGfxEntity(o); - seq_table_view_->resizeColumnsToContents(); - seq_table_view_->resizeRowsToContents(); - } -} - -void SequenceViewerV2::NodeRemoved(const gfx::GfxNodeP& node) -{ - if (gfx::EntityP o=boost::dynamic_pointer_cast<gfx::Entity>(node)) { - model_->RemoveGfxEntity(o); - } -} - -void SequenceViewerV2::SelectionModelChanged(const QItemSelection& sel, const QItemSelection& desel) -{ - gfx::Scene::Instance().DetachObserver(this); - model_->SelectionChanged(sel, desel); - gfx::Scene::Instance().AttachObserver(this); -} - -void SequenceViewerV2::SelectionChanged(const gfx::GfxObjP& o, - const mol::EntityView& view) -{ - disconnect(seq_table_view_->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), this, SLOT(SelectionModelChanged(const QItemSelection&, const QItemSelection&))); - QItemSelectionModel* model = seq_table_view_->selectionModel(); - gfx::EntityP entity=boost::dynamic_pointer_cast<gfx::Entity>(o); - if(entity){ - const QModelIndexList& list = model_->GetModelIndexes(entity, view); - QSet<int> rows_visited; - for(int i = 0; i<list.size(); i++){ - int row =list[i].row(); - if(!rows_visited.contains(row)){ - model->select(list[i],QItemSelectionModel::Rows|QItemSelectionModel::Deselect); - rows_visited.insert(row); - } - } - for(int i = 0; i<list.size(); i++){ - model->select(list[i],QItemSelectionModel::Select); - } - } - connect(seq_table_view_->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), this, SLOT(SelectionModelChanged(const QItemSelection&, const QItemSelection&))); -} - -void SequenceViewerV2::DoubleClicked(const QModelIndex& index) -{ - disconnect(seq_table_view_->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), this, SLOT(SelectionModelChanged(const QItemSelection&, const QItemSelection&))); - model_->DoubleClicked(index); - connect(seq_table_view_->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), this, SLOT(SelectionModelChanged(const QItemSelection&, const QItemSelection&))); -} - -void SequenceViewerV2::MouseWheelEvent(QWheelEvent* event) -{ - int delta = event->delta(); - if (event->orientation() == Qt::Vertical) { - if(delta>0){ - model_->ZoomIn(); - seq_table_view_->viewport()->update(); - seq_table_view_->resizeColumnsToContents(); - seq_table_view_->resizeRowsToContents(); - } - else if(delta<0){ - model_->ZoomOut(); - seq_table_view_->viewport()->update(); - seq_table_view_->resizeColumnsToContents(); - seq_table_view_->resizeRowsToContents(); - } - } - event->accept(); -} - -SequenceViewerV2::~SequenceViewerV2(){ - gfx::Scene::Instance().DetachObserver(this); -} - -}} diff --git a/modules/gui/src/sequence/view_object.cc b/modules/gui/src/sequence/view_object.cc deleted file mode 100644 index e422027e7105fa95277e89be52ce5f70aa110ddd..0000000000000000000000000000000000000000 --- a/modules/gui/src/sequence/view_object.cc +++ /dev/null @@ -1,232 +0,0 @@ -//------------------------------------------------------------------------------ -// This file is part of the OpenStructure project <www.openstructure.org> -// -// Copyright (C) 2008-2010 by the OpenStructure authors -// -// This library is free software; you can redistribute it and/or modify it under -// the terms of the GNU Lesser General Public License as published by the Free -// Software Foundation; either version 3.0 of the License, or (at your option) -// any later version. -// This library is distributed in the hope that it will be useful, but WITHOUT -// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -// details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this library; if not, write to the Free Software Foundation, Inc., -// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -//------------------------------------------------------------------------------ - -/* - Author: Stefan Scheuber - */ - - -#include <QtGui> - -#include <ost/mol/mol.hh> -#include <ost/mol/view_op.hh> - -#include "sequence_row.hh" -#include "secstr_row.hh" -#include "title_row.hh" - -#include "painter.hh" -#include "seq_secstr_painter.hh" -#include "seq_selection_painter.hh" -#include "seq_text_painter.hh" -#include "tick_painter.hh" - -#include "view_object.hh" - -namespace ost { namespace gui { - -ViewObject::ViewObject(seq::SequenceList& sequences, const QList<QString>& names, QObject *parent): QObject(parent) -{ - if(names.size() == sequences.GetCount()){ - for(int i=0; i<sequences.GetCount(); i++){ - seq::SequenceHandle seq = sequences[i]; - this->AddSequence(seq, names[i]); - } - } -} - -ViewObject::ViewObject(seq::SequenceHandle& sequence, const QString& name, QObject *parent): QObject(parent), entity_(gfx::EntityP()) -{ - this->AddSequence(sequence, name); -} - -ViewObject::ViewObject(mol::ChainView& chain, const QString& name, QObject *parent): QObject(parent), entity_(gfx::EntityP()) -{ - this->AddChain(chain, name); -} - -ViewObject::ViewObject(gfx::EntityP& entity, QObject* parent): QObject(parent), entity_(entity) -{ - mol::EntityView view =entity->GetView(); - for (mol::ChainViewList::const_iterator c=view.GetChainList().begin(), - e1=view.GetChainList().end(); c!=e1; ++c) { - mol::ChainView chain=*c; - QString name = QString(entity->GetName().c_str()); - if (chain.GetName()!="" && chain.GetName()!=" ") { - name= name + " ("+chain.GetName().c_str()+")"; - } - this->AddChain(chain, name); - } -} - -ViewObject::ViewObject(QObject* parent): QObject(parent) -{ - TitleRow* new_row = new TitleRow(this); - Painter* p = new TickPainter(this); - new_row->InsertPainter(p); - rows_.append(new_row); -} - -void ViewObject::InsertRow(int pos, BaseRow* row) -{ - if(pos >= 0 && pos <= rows_.size()){ - rows_.insert(pos,row); - } -} - -void ViewObject::RemoveRow(BaseRow* row) -{ - rows_.removeAll(row); -} - -BaseRow* ViewObject::GetRow(int pos) -{ - if(pos >= 0 && pos < rows_.size()){ - return rows_[pos]; - } - return NULL; -} - -int ViewObject::GetRowCount() -{ - return rows_.size(); -} - -void ViewObject::AddSequence(seq::SequenceHandle& sequence, const QString& name) -{ - SequenceRow* new_row = new SequenceRow(name, sequence, this); - Painter* p = new SeqSelectionPainter(this); - new_row->InsertPainter(p); - p = new SeqTextPainter(this); - new_row->InsertPainter(p); - rows_.append(new_row); -} - -void ViewObject::AddChain(mol::ChainView& chain, const QString& name) -{ - SecStrRow* new_row = new SecStrRow(name, chain, this); - Painter* p = new SeqSelectionPainter(this); - new_row->InsertPainter(p); - p = new SeqSecStrPainter(this); - new_row->InsertPainter(p); - p = new SeqTextPainter(this); - new_row->InsertPainter(p); - rows_.append(new_row); -} - -void ViewObject::AttachGfxObject(gfx::EntityP& ent) -{ - entity_ = ent; -} - -gfx::EntityP& ViewObject::GetGfxObject() -{ - return entity_; -} - -void ViewObject::SetSelection(int row, const QSet<int>& added, const QSet<int>& removed) -{ - if(SequenceRow* sequence_row = qobject_cast<SequenceRow*>(rows_[row])){ - sequence_row->SetSelection(added,removed); - } -} - -QVariant ViewObject::GetData(int row, int column, int role) -{ - if(row<0 || row >= rows_.size())return QVariant(); - - return rows_[row]->GetData(column,role); -} - -int ViewObject::GetMaxColumnCount() const -{ - int columns = 0; - for(int i = 0; i < rows_.size(); i++){ - int col_length = rows_[i]->GetColumnCount(); - if(columns < col_length){ - columns = col_length; - } - } - return columns; -} - -bool ViewObject::SetData(int row, int column, const QVariant& value, int role) -{ - if(row<0 || row >= rows_.size())return false; - - return rows_[row]->SetData(column, value, role); -} - -void ViewObject::DoubleClicked(int row, int column) -{ - if(row>=0 || row < rows_.size()){ - rows_[row]->DoubleClicked(column); - } -} - -void ViewObject::ZoomIn() -{ - for(int i=0; i< rows_.size(); i++){ - rows_[i]->ZoomIn(); - } -} - -void ViewObject::ZoomOut() -{ - for(int i=0; i< rows_.size(); i++){ - rows_[i]->ZoomOut(); - } -} - -QMap<int, QList<int> > ViewObject::GetIndexesForView(const mol::EntityView& view) -{ - if(view.GetChainCount()==0){ - return QMap<int, QList<int> >(); - } - else{ - QMap<int, QList<int> > selected_indexes; - for(int i=0; i< rows_.size(); i++){ - if(SecStrRow* secstr_row = qobject_cast<SecStrRow*>(rows_[i])){ - mol::ChainView dst_chain=(secstr_row->GetChain()); - seq::SequenceHandle seq = secstr_row->GetSequence(); - if (mol::ChainView src_chain=view.FindChain(dst_chain.GetName())) { - // for each residue in the selection deduce index in sequence - for (mol::ResidueViewList::const_iterator j=src_chain.GetResidueList().begin(), - e2=src_chain.GetResidueList().end(); j!=e2; ++j) { - mol::ResidueView dst_res=dst_chain.FindResidue(j->GetHandle()); - assert(dst_res.IsValid()); - int p=dst_res.GetIndex()+1; - assert(p>=0 && p<=seq.GetLength()); - selected_indexes[i].append(p); - } - } - } - } - return selected_indexes; - } -} - -Qt::ItemFlags ViewObject::Flags(int row, int column) const -{ - if(row<0 || row >= rows_.size())return Qt::NoItemFlags; - - return rows_[row]->Flags(column); -} - -}} diff --git a/modules/gui/src/sequence_viewer/align_properties_painter.cc b/modules/gui/src/sequence_viewer/align_properties_painter.cc new file mode 100644 index 0000000000000000000000000000000000000000..e51c0536aa512337dca4b159e35f83fddb29ae89 --- /dev/null +++ b/modules/gui/src/sequence_viewer/align_properties_painter.cc @@ -0,0 +1,78 @@ +//------------------------------------------------------------------------------ +// This file is part of the OpenStructure project <www.openstructure.org> +// +// Copyright (C) 2008-2010 by the OpenStructure authors +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation; either version 3.0 of the License, or (at your option) +// any later version. +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +//------------------------------------------------------------------------------ + +/* + Author: Stefan Scheuber + */ + + +#include <QtGui> + +#include "align_properties_painter.hh" + +namespace ost { namespace gui { + +namespace { + +QMap<QString,QColor> GetColorMap(){ + QMap<QString,QColor> map; + map["G"]=QColor(175,175,175,100); + map["A"]=QColor(175,175,175,100); + map["V"]=QColor(175,175,175,100); + map["L"]=QColor(175,175,175,100); + map["I"]=QColor(175,175,175,100); + map["F"]=QColor(255,165,100); + map["Y"]=QColor(255,165,100); + map["W"]=QColor(255,165,100); + map["C"]=QColor(255,255,0,100); + map["M"]=QColor(255,255,0,100); + map["S"]=QColor(0,255,0,100); + map["T"]=QColor(0,255,0,100); + map["K"]=QColor(255,0,0,100); + map["R"]=QColor(255,0,0,100); + map["H"]=QColor(255,0,0,100); + map["D"]=QColor(0,0,255,100); + map["E"]=QColor(0,0,255,100); + map["N"]=QColor(0,0,255,100); + map["Q"]=QColor(0,0,255,100); + map["P"]=QColor(0,255,255,100); + return map; +} + +} + +QMap<QString,QColor> AlignPropertiesPainter::color_map_ = GetColorMap(); + + +AlignPropertiesPainter::AlignPropertiesPainter(QObject* parent) + : Painter(parent) +{} + +void AlignPropertiesPainter::Paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index){ + painter->save(); + if (index.column()>0){ + QString text = index.data(Qt::DisplayRole).toString(); + if(color_map_.contains(text)){ + painter->fillRect(option.rect, color_map_[text]); + } + } + painter->restore(); +} + +}} diff --git a/modules/gui/pymod/sequence_viewer_proxyV2.hh b/modules/gui/src/sequence_viewer/align_properties_painter.hh similarity index 70% rename from modules/gui/pymod/sequence_viewer_proxyV2.hh rename to modules/gui/src/sequence_viewer/align_properties_painter.hh index 7d7e1f269acd559d1cfc6505056ee7aa9c7ca8c7..d33331cc6bd8c188379de76b0443ad5aeef06433 100644 --- a/modules/gui/pymod/sequence_viewer_proxyV2.hh +++ b/modules/gui/src/sequence_viewer/align_properties_painter.hh @@ -16,30 +16,29 @@ // along with this library; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA //------------------------------------------------------------------------------ -#ifndef OST_GUI_SEQUENCE_VIEWER_PROXY_V2_HH -#define OST_GUI_SEQUENCE_VIEWER_PROXY_V2_HH +#ifndef OST_SEQUENCE_VIEWER_ALIGN_PROPERTIES_PAINTER +#define OST_SEQUENCE_VIEWER_ALIGN_PROPERTIES_PAINTER -#include <ost/gui/sequence/sequence_viewer.hh> +/* + Author: Stefan Scheuber + */ -#include "sip_handler.hh" +#include <QObject> + +#include "painter.hh" namespace ost { namespace gui { -class SequenceViewerProxyV2 : public SipHandler<SequenceViewerV2> { + +class AlignPropertiesPainter : public Painter +{ + Q_OBJECT public: - SequenceViewerProxyV2(SequenceViewerV2* seq_viewer=new SequenceViewerV2()): - SipHandler<SequenceViewerV2>(seq_viewer) - { } - - void Show() - { - return Me()->show(); - } - void Hide() - { - return Me()->hide(); - } + AlignPropertiesPainter(QObject* parent = 0); + void Paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index); +private: + static QMap<QString,QColor> color_map_; }; }} diff --git a/modules/gui/src/sequence_viewer/alignment_view_object.cc b/modules/gui/src/sequence_viewer/alignment_view_object.cc new file mode 100644 index 0000000000000000000000000000000000000000..9aa23319419f5fd244c60d4c3ec3c980b6153d85 --- /dev/null +++ b/modules/gui/src/sequence_viewer/alignment_view_object.cc @@ -0,0 +1,212 @@ +//------------------------------------------------------------------------------ +// This file is part of the OpenStructure project <www.openstructure.org> +// +// Copyright (C) 2008-2010 by the OpenStructure authors +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation; either version 3.0 of the License, or (at your option) +// any later version. +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +//------------------------------------------------------------------------------ + +/* + Author: Stefan Scheuber + */ + + +#include <QtGui> + +#include <ost/mol/mol.hh> +#include <ost/mol/view_op.hh> + +#include <ost/seq/aligned_region.hh> +#include <ost/seq/alg/conservation.hh> + +#include "sequence_row.hh" +#include "secstr_row.hh" + +#include "painter.hh" +#include "background_painter.hh" +#include "seq_secstr_painter.hh" +#include "seq_selection_painter.hh" +#include "seq_text_painter.hh" + +#include "alignment_view_object.hh" + +namespace ost { namespace gui { + +namespace { +QMap<QString,int> GetGroupMap(){ + QMap<QString,int> map; + map["G"]=1; + map["A"]=1; + map["V"]=1; + map["L"]=1; + map["I"]=1; + map["F"]=2; + map["Y"]=2; + map["W"]=2; + map["C"]=3; + map["M"]=3; + map["S"]=4; + map["T"]=4; + map["K"]=5; + map["R"]=5; + map["H"]=5; + map["D"]=6; + map["E"]=6; + map["N"]=6; + map["Q"]=6; + map["P"]=7; + return map; +} + +QColor GetColor(int cons){ + int color = 255 - int((float(cons) / 100) * 200); + return QColor(color,color,color); +} + +QColor GetForeGroundColor(QColor background){ + if(background == Qt::transparent){ + return Qt::black; + } + int gray = 255 - background.red(); + return QColor(gray,gray,gray); +} + +} + +QMap<QString,int> AlignmentViewObject::group_map_ = GetGroupMap(); + + +const QString AlignmentViewObject::conservation_mode_1 = "Highlight conservation 1"; +const QString AlignmentViewObject::conservation_mode_2 = "Highlight conservation 2"; + +AlignmentViewObject::AlignmentViewObject(const seq::AlignmentHandle& alignment, QObject* parent): SequenceViewObject(parent), alignment_(alignment) +{ + for(int i=0; i<alignment.GetCount(); i++){ + seq::SequenceHandle seq_handle = alignment.GetSequence(i).Copy(); + this->AddSequence(seq_handle, seq_handle.GetName().c_str()); + } + + std::vector<Real> values = seq::alg::Conservation(alignment,false); + + gradient_.SetColorAt(0,gfx::Color(0,0,1)); + gradient_.SetColorAt(0.5,gfx::Color(1,1,1)); + gradient_.SetColorAt(1,gfx::Color(1,0,0)); + //Calculate Conservation Mode 1 + for(unsigned int i=0; i<values.size(); i++){ + gfx::Color color = gradient_.GetColorAt(values[i]); + conservation_1_[i] = QColor(color.Red()*255,color.Green()*255,color.Blue()*255,100); + } + + //Calculate Conservation Mode 2 + for(int j=0; j<alignment.GetLength(); j++){ + int group = 0; + QString element = ""; + for(int i=0; i<alignment.GetCount();i++){ + QString code = QString(alignment.GetOneLetterCode(i,j)); + if(element.size()==0){ + element = code; + } + else if (element != code){ + element = " "; + } + if(group_map_.contains(code) && group>=0){ + if(group == 0) { + group = group_map_[code]; + } + else if(group_map_[code] != group){ + group = -1; + } + } + else{ + group = -1; + } + + } + if(element.size()==1){ + conservation_2_[j] = QColor(175,175,175); + } + else if(group > 0){ + conservation_2_[j] = QColor(200,200,200); + } + else{ + conservation_2_[j] = Qt::transparent; + } + } + this->AddDisplayMode(conservation_mode_1); + this->AddDisplayMode(conservation_mode_2); +} + + +QVariant AlignmentViewObject::GetData(int row, int column, int role) +{ + if(column > 0){ + if(this->GetCurrentDisplayMode() == conservation_mode_1){ + if(role == Qt::UserRole+3 ){ + if(column -1 < conservation_1_.size()){ + return QVariant(conservation_1_[column-1]); + } + return QVariant(Qt::transparent); + } + + if(role == Qt::ForegroundRole){ + if(column -1 < conservation_1_.size()){ + if(conservation_1_[column-1].red()>128){ + return QVariant(Qt::black); + } + else{ + return QVariant(Qt::white); + } + } + return QVariant(Qt::transparent); + } + } + else if(this->GetCurrentDisplayMode() == conservation_mode_2){ + if(role == Qt::UserRole+3 ){ + if(column -1 < conservation_2_.size()){ + return QVariant(conservation_2_[column-1]); + } + return QVariant(Qt::transparent); + } + if(role == Qt::ForegroundRole){ + if(column -1 < conservation_2_.size()){ + return QVariant(Qt::black); + } + return QVariant(Qt::transparent); + } + } + } + return BaseViewObject::GetData(row,column,role); +} + +void AlignmentViewObject::SetDisplayMode(const QString& mode) +{ + if(this->display_modes_.contains(mode) && mode != this->GetCurrentDisplayMode()){ + if(mode == conservation_mode_1 || mode == conservation_mode_2){ + for(int i=0 ; i<this->GetRowCount(); i++){ + BaseRow* row = this->GetRow(i); + row->RemovePainter(seq_secondary_structure_painter); + row->RemovePainter(align_properties_painter); + row->InsertPainter(conservation_painter,1); + } + } + } + SequenceViewObject::SetDisplayMode(mode); +} + +const seq::AlignmentHandle& AlignmentViewObject::GetAlignment() +{ + return alignment_; +} + +}} diff --git a/modules/gui/src/sequence_viewer/alignment_view_object.hh b/modules/gui/src/sequence_viewer/alignment_view_object.hh new file mode 100644 index 0000000000000000000000000000000000000000..b8fee2800d9e766211590b6b263c3cd02562456e --- /dev/null +++ b/modules/gui/src/sequence_viewer/alignment_view_object.hh @@ -0,0 +1,61 @@ +//------------------------------------------------------------------------------ +// This file is part of the OpenStructure project <www.openstructure.org> +// +// Copyright (C) 2008-2010 by the OpenStructure authors +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation; either version 3.0 of the License, or (at your option) +// any later version. +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +//------------------------------------------------------------------------------ +#ifndef OST_SEQUENCE_VIEWER_ALIGNMENT_VIEW_OBJECT +#define OST_SEQUENCE_VIEWER_ALIGNMENT_VIEW_OBJECT + +/* + Author: Stefan Scheuber + */ + +#include <ost/seq/alignment_handle.hh> + +#include <ost/gfx/gradient.hh> + +#include "sequence_view_object.hh" + +namespace ost { namespace gui { + +class AlignmentViewObject : public SequenceViewObject +{ + Q_OBJECT + +public: + AlignmentViewObject(const seq::AlignmentHandle& alignment, QObject* parent = 0); + + QVariant GetData(int row, int column, int role); + const seq::AlignmentHandle& GetAlignment(); + + void SetDisplayMode(const QString& mode); + +private: + gfx::Gradient gradient_; + seq::AlignmentHandle alignment_; + QMap<int, QColor> conservation_1_; + QMap<int, QColor> conservation_2_; + + static QMap<QString,int> group_map_; + + static const QString conservation_mode_1; + static const QString conservation_mode_2; +}; + + +}} + +#endif diff --git a/modules/gui/src/sequence_viewer/background_painter.cc b/modules/gui/src/sequence_viewer/background_painter.cc new file mode 100644 index 0000000000000000000000000000000000000000..25cf4c65022a3eb0783d7e678d93ca1cabe8e1ff --- /dev/null +++ b/modules/gui/src/sequence_viewer/background_painter.cc @@ -0,0 +1,51 @@ +//------------------------------------------------------------------------------ +// This file is part of the OpenStructure project <www.openstructure.org> +// +// Copyright (C) 2008-2010 by the OpenStructure authors +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation; either version 3.0 of the License, or (at your option) +// any later version. +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +//------------------------------------------------------------------------------ + +/* + Author: Stefan Scheuber + */ + + +#include <QtGui> + +#include "background_painter.hh" + +namespace ost { namespace gui { + +BackgroundPainter::BackgroundPainter(QObject* parent) + : Painter(parent) +{} + +void BackgroundPainter::Paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index){ + painter->save(); + if (index.column()>0 && (index.column()-1)%10 < 5){ + painter->fillRect(option.rect, QColor(240,240,240)); + + } + else{ + painter->fillRect(option.rect, QColor(255,255,255)); + } + if(index.row()>0 && (index.column())%10 == 0){ + painter->setPen(QPen(QColor(135,135,135))); + painter->drawLine(option.rect.topRight(),option.rect.bottomRight()); + } + painter->restore(); +} + +}} diff --git a/modules/base/src/integrity_error.cc b/modules/gui/src/sequence_viewer/background_painter.hh similarity index 71% rename from modules/base/src/integrity_error.cc rename to modules/gui/src/sequence_viewer/background_painter.hh index ced74b0c9eabd222cbc3283fdd4fe96bcf28ad5c..942e1dde5bd9b67326862eaf605de1436c962ab7 100644 --- a/modules/base/src/integrity_error.cc +++ b/modules/gui/src/sequence_viewer/background_painter.hh @@ -16,14 +16,28 @@ // along with this library; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA //------------------------------------------------------------------------------ -#include "integrity_error.hh" -#include <ost/message.hh> +#ifndef OST_SEQUENCE_VIEWER_BACKGROUND_PAINTER +#define OST_SEQUENCE_VIEWER_BACKGROUND_PAINTER -namespace ost { -IntegrityError::IntegrityError(const String& msg): - Error(msg) +/* + Author: Stefan Scheuber + */ + +#include <QObject> + +#include "painter.hh" + +namespace ost { namespace gui { + +class BackgroundPainter : public Painter { - -} + Q_OBJECT +public: + BackgroundPainter(QObject* parent = 0); + void Paint(QPainter *painter, const QStyleOptionViewItem &option, + const QModelIndex &index); +}; + +}} -} +#endif diff --git a/modules/gui/src/sequence/base_row.cc b/modules/gui/src/sequence_viewer/base_row.cc similarity index 97% rename from modules/gui/src/sequence/base_row.cc rename to modules/gui/src/sequence_viewer/base_row.cc index e2a57450bba50b67f65f9c8c32d5eed2706d0a8f..16dfb0af3831eda02d11e32f964374b5298c5247 100644 --- a/modules/gui/src/sequence/base_row.cc +++ b/modules/gui/src/sequence_viewer/base_row.cc @@ -130,6 +130,9 @@ Qt::ItemFlags BaseRow::Flags(int column) const void BaseRow::DoubleClicked(int column) { } +void BaseRow::SetSelection(const QSet<int>& added, const QSet<int>& removed) +{ } + void BaseRow::ZoomIn() { QFont font = this->GetFont(); diff --git a/modules/gui/src/sequence/base_row.hh b/modules/gui/src/sequence_viewer/base_row.hh similarity index 96% rename from modules/gui/src/sequence/base_row.hh rename to modules/gui/src/sequence_viewer/base_row.hh index 3a69ca0e6b62fb0f1b7678ce9eab10e57f2cf47a..6f20d872b7ff431bb4ba3799e7f5af66c6f52d20 100644 --- a/modules/gui/src/sequence/base_row.hh +++ b/modules/gui/src/sequence_viewer/base_row.hh @@ -59,6 +59,7 @@ public: virtual bool SetData(int column, const QVariant& value, int role); virtual Qt::ItemFlags Flags(int column) const; virtual void DoubleClicked(int column); + virtual void SetSelection(const QSet<int>& added, const QSet<int>& removed); virtual void ZoomIn(); virtual void ZoomOut(); diff --git a/modules/gui/src/sequence_viewer/base_view_object.cc b/modules/gui/src/sequence_viewer/base_view_object.cc new file mode 100644 index 0000000000000000000000000000000000000000..72953aa3ea0aaeae9a5e562c9fb9ebf35a8cc255 --- /dev/null +++ b/modules/gui/src/sequence_viewer/base_view_object.cc @@ -0,0 +1,144 @@ +//------------------------------------------------------------------------------ +// This file is part of the OpenStructure project <www.openstructure.org> +// +// Copyright (C) 2008-2010 by the OpenStructure authors +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation; either version 3.0 of the License, or (at your option) +// any later version. +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +//------------------------------------------------------------------------------ + +/* + Author: Stefan Scheuber + */ + + +#include <QtGui> + +#include "base_view_object.hh" + +namespace ost { namespace gui { + +BaseViewObject::BaseViewObject(QObject* parent): QObject(parent) +{ } + +void BaseViewObject::InsertRow(int pos, BaseRow* row) +{ + if(pos >= 0 && pos <= rows_.size()){ + rows_.insert(pos,row); + } +} + +void BaseViewObject::RemoveRow(BaseRow* row) +{ + rows_.removeAll(row); +} + +BaseRow* BaseViewObject::GetRow(int pos) +{ + if(pos >= 0 && pos < rows_.size()){ + return rows_[pos]; + } + return NULL; +} + +int BaseViewObject::GetRowCount() +{ + return rows_.size(); +} + +void BaseViewObject::SetSelection(int row, const QSet<int>& added, const QSet<int>& removed) +{ + if(row>=0 && row < rows_.size()){ + rows_[row]->SetSelection(added,removed); + } +} + +QVariant BaseViewObject::GetData(int row, int column, int role) +{ + if(row<0 || row >= rows_.size())return QVariant(); + + return rows_[row]->GetData(column,role); +} + +int BaseViewObject::GetMaxColumnCount() const +{ + int columns = 0; + for(int i = 0; i < rows_.size(); i++){ + int col_length = rows_[i]->GetColumnCount(); + if(columns < col_length){ + columns = col_length; + } + } + return columns; +} + +bool BaseViewObject::SetData(int row, int column, const QVariant& value, int role) +{ + if(row<0 || row >= rows_.size())return false; + + return rows_[row]->SetData(column, value, role); +} + +const QStringList& BaseViewObject::GetDisplayModes() +{ + return display_modes_; +} + +const QString& BaseViewObject::GetCurrentDisplayMode() +{ + return current_display_mode_; +} + +void BaseViewObject::SetDisplayMode(const QString& mode) +{ + if(display_modes_.contains(mode)){ + this->current_display_mode_ = mode; + } +} + +void BaseViewObject::AddDisplayMode(const QString& mode) +{ + if(!display_modes_.contains(mode)){ + this->display_modes_.append(mode); + } +} + +void BaseViewObject::DoubleClicked(int row, int column) +{ + if(row>=0 || row < rows_.size()){ + rows_[row]->DoubleClicked(column); + } +} + +void BaseViewObject::ZoomIn() +{ + for(int i=0; i< rows_.size(); i++){ + rows_[i]->ZoomIn(); + } +} + +void BaseViewObject::ZoomOut() +{ + for(int i=0; i< rows_.size(); i++){ + rows_[i]->ZoomOut(); + } +} + +Qt::ItemFlags BaseViewObject::Flags(int row, int column) const +{ + if(row<0 || row >= rows_.size())return Qt::NoItemFlags; + + return rows_[row]->Flags(column); +} + +}} diff --git a/modules/gui/src/sequence/sequence_viewer.hh b/modules/gui/src/sequence_viewer/base_view_object.hh similarity index 52% rename from modules/gui/src/sequence/sequence_viewer.hh rename to modules/gui/src/sequence_viewer/base_view_object.hh index 3940c68fad19cfed610c9911242cb74cfccbcd98..90526bfa36011a33f7c75890f59a5d43f4f8e3e2 100644 --- a/modules/gui/src/sequence/sequence_viewer.hh +++ b/modules/gui/src/sequence_viewer/base_view_object.hh @@ -16,52 +16,58 @@ // along with this library; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA //------------------------------------------------------------------------------ -#ifndef OST_SEQUENCE_VIEWER_SEQUENCE_VIEWER -#define OST_SEQUENCE_VIEWER_SEQUENCE_VIEWER +#ifndef OST_SEQUENCE_VIEWER_BASE_VIEW_OBJECT +#define OST_SEQUENCE_VIEWER_BASE_VIEW_OBJECT /* Author: Stefan Scheuber */ -#include <QWidget> +#include <QObject> +#include <QList> -#include <ost/gfx/scene.hh> -#include <ost/gfx/gfx_object.hh> +#include "base_row.hh" -#include <ost/gui/widget.hh> - -#include <ost/gui/module_config.hh> - -#include "sequence_model.hh" -#include "sequence_table_view.hh" namespace ost { namespace gui { -/// \brief QTableView with first column not moving -class DLLEXPORT_OST_GUI SequenceViewerV2 : public Widget, public gfx::SceneObserver { +class BaseViewObject : public QObject +{ Q_OBJECT + + public: - SequenceViewerV2(QWidget* parent=NULL); - ~SequenceViewerV2(); + BaseViewObject(QObject* parent = 0); - virtual void NodeAdded(const gfx::GfxNodeP& node); - virtual void NodeRemoved(const gfx::GfxNodeP& node); - virtual void SelectionChanged(const gfx::GfxObjP& o, const mol::EntityView& view); + void InsertRow(int pos, BaseRow* row); + void RemoveRow(BaseRow* row); + BaseRow* GetRow(int pos); + int GetRowCount(); + int GetMaxColumnCount() const; - virtual bool Restore(const QString&){return true;}; - virtual bool Save(const QString&){return true;}; + virtual void SetSelection(int row, const QSet<int>& added, const QSet<int>& removed); -private: - SequenceModel* model_; - SequenceTableView* seq_table_view_; + virtual QVariant GetData(int row, int column, int role); + virtual bool SetData(int row, int column, const QVariant& value, int role); + virtual Qt::ItemFlags Flags(int row, int column) const; -private slots: - void SelectionModelChanged(const QItemSelection&, const QItemSelection&); - void DoubleClicked(const QModelIndex& index); - void MouseWheelEvent(QWheelEvent* event); + virtual const QStringList& GetDisplayModes(); + virtual const QString& GetCurrentDisplayMode(); + virtual void SetDisplayMode(const QString& mode); + void DoubleClicked(int row, int column); + void ZoomIn(); + void ZoomOut(); + +protected: + virtual void AddDisplayMode(const QString& mode); + + QList<BaseRow*> rows_; + QString current_display_mode_; + QStringList display_modes_; }; + }} #endif diff --git a/modules/gui/pymod/export_sequence_viewerV2.cc b/modules/gui/src/sequence_viewer/conservation_painter.cc similarity index 67% rename from modules/gui/pymod/export_sequence_viewerV2.cc rename to modules/gui/src/sequence_viewer/conservation_painter.cc index cd010952fb9b6a32a06b85aafbeac16e08ced672..7bab56edccd81c7fa29edbebc4d1789d038102af 100644 --- a/modules/gui/pymod/export_sequence_viewerV2.cc +++ b/modules/gui/src/sequence_viewer/conservation_painter.cc @@ -16,24 +16,30 @@ // along with this library; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA //------------------------------------------------------------------------------ -#include <boost/python.hpp> -#include <ost/gui/sequence/sequence_viewer.hh> +/* + Author: Stefan Scheuber + */ -#include "sip_handler.hh" -using namespace boost::python; -using namespace ost; -using namespace ost::gui; +#include <QtGui> +#include "conservation_painter.hh" -void export_SequenceViewerV2() -{ - class_<SequenceViewerV2, boost::noncopyable >("SequenceViewerV2",init<>()) - .def("Show", &SequenceViewerV2::show) - .def("Hide", &SequenceViewerV2::hide) - .def("GetQObject",&get_py_qobject<SequenceViewerV2>) - .add_property("qobject", &get_py_qobject<SequenceViewerV2>) - ; +namespace ost { namespace gui { + + +ConservationPainter::ConservationPainter(QObject* parent) + : Painter(parent) +{} + +void ConservationPainter::Paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index){ + painter->save(); + if (index.column()>0){ + QColor cons = index.data(Qt::UserRole+3).value<QColor>(); + painter->fillRect(option.rect, cons); + } + painter->restore(); } +}} diff --git a/modules/gui/src/sequence_viewer/conservation_painter.hh b/modules/gui/src/sequence_viewer/conservation_painter.hh new file mode 100644 index 0000000000000000000000000000000000000000..c6549f661c57e579ce07c01fd0ba027fb120a563 --- /dev/null +++ b/modules/gui/src/sequence_viewer/conservation_painter.hh @@ -0,0 +1,44 @@ +//------------------------------------------------------------------------------ +// This file is part of the OpenStructure project <www.openstructure.org> +// +// Copyright (C) 2008-2010 by the OpenStructure authors +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation; either version 3.0 of the License, or (at your option) +// any later version. +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +//------------------------------------------------------------------------------ +#ifndef OST_SEQUENCE_VIEWER_CONSERVATION_PAINTER +#define OST_SEQUENCE_VIEWER_CONSERVATION_PAINTER + +/* + Author: Stefan Scheuber + */ + +#include <QObject> + +#include "painter.hh" + +namespace ost { namespace gui { + + + +class ConservationPainter : public Painter +{ + Q_OBJECT +public: + ConservationPainter(QObject* parent = 0); + void Paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index); +}; + +}} + +#endif diff --git a/modules/gui/src/sequence/painter.hh b/modules/gui/src/sequence_viewer/painter.hh similarity index 100% rename from modules/gui/src/sequence/painter.hh rename to modules/gui/src/sequence_viewer/painter.hh diff --git a/modules/gui/src/sequence/secstr_row.cc b/modules/gui/src/sequence_viewer/secstr_row.cc similarity index 98% rename from modules/gui/src/sequence/secstr_row.cc rename to modules/gui/src/sequence_viewer/secstr_row.cc index e6017f35724e1f059b952bab68bf0078522e34f9..180a47469bc97f931ce713e74574ee20be3083a7 100644 --- a/modules/gui/src/sequence/secstr_row.cc +++ b/modules/gui/src/sequence_viewer/secstr_row.cc @@ -33,7 +33,7 @@ namespace ost { namespace gui { -SecStrRow::SecStrRow(const QString& name, mol::ChainView& chain, ViewObject* parent) : SequenceRow(name,parent) +SecStrRow::SecStrRow(const QString& name, mol::ChainView& chain, SequenceViewObject* parent) : SequenceRow(name,parent) { this->SetChain(chain); } void SecStrRow::SetSequence(seq::SequenceHandle& sequence) diff --git a/modules/gui/src/sequence/secstr_row.hh b/modules/gui/src/sequence_viewer/secstr_row.hh similarity index 95% rename from modules/gui/src/sequence/secstr_row.hh rename to modules/gui/src/sequence_viewer/secstr_row.hh index f52766032ef531d5583f38c621fb22477d446143..4b6bd2762457b2545807b344f1953362543f0347 100644 --- a/modules/gui/src/sequence/secstr_row.hh +++ b/modules/gui/src/sequence_viewer/secstr_row.hh @@ -38,7 +38,7 @@ class SecStrRow : public SequenceRow Q_OBJECT public: - SecStrRow(const QString& name, mol::ChainView& chain, ViewObject* parent); + SecStrRow(const QString& name, mol::ChainView& chain, SequenceViewObject* parent); virtual QVariant GetData(int column, int role) const; virtual void DoubleClicked(int column); diff --git a/modules/gui/src/sequence/seq_secstr_painter.cc b/modules/gui/src/sequence_viewer/seq_secstr_painter.cc similarity index 100% rename from modules/gui/src/sequence/seq_secstr_painter.cc rename to modules/gui/src/sequence_viewer/seq_secstr_painter.cc diff --git a/modules/gui/src/sequence/seq_secstr_painter.hh b/modules/gui/src/sequence_viewer/seq_secstr_painter.hh similarity index 100% rename from modules/gui/src/sequence/seq_secstr_painter.hh rename to modules/gui/src/sequence_viewer/seq_secstr_painter.hh diff --git a/modules/gui/src/sequence/seq_selection_painter.cc b/modules/gui/src/sequence_viewer/seq_selection_painter.cc similarity index 77% rename from modules/gui/src/sequence/seq_selection_painter.cc rename to modules/gui/src/sequence_viewer/seq_selection_painter.cc index e9b0c4d5c8723a51c9277a03946c9d5d0968796a..8473171967a9f398e8e9a9883197ab54ff605146 100644 --- a/modules/gui/src/sequence/seq_selection_painter.cc +++ b/modules/gui/src/sequence_viewer/seq_selection_painter.cc @@ -29,27 +29,25 @@ namespace ost { namespace gui { SeqSelectionPainter::SeqSelectionPainter(QObject* parent) - : Painter(parent) -{} + : Painter(parent), focus_color_(255,0,0,0), mouse_over_color_(240,240,240,192) +{ + +} void SeqSelectionPainter::Paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index){ painter->save(); - if ((index.column()-1)%10 > 4){ - painter->fillRect(option.rect, QColor(240,240,240)); - - } - if((index.column())%10 == 0){ - painter->setPen(QPen(QColor(135,135,135))); - painter->drawLine(option.rect.topRight(),option.rect.bottomRight()); - } + /* if (option.state & QStyle::State_HasFocus){ - painter->fillRect(option.rect, QColor(240,240,0,60)); + painter->fillRect(option.rect, focus_color_); } + */ if (option.state & QStyle::State_MouseOver){ - painter->fillRect(option.rect, QColor(240,240,240,128)); + painter->fillRect(option.rect, mouse_over_color_); } if (option.state & QStyle::State_Selected){ - painter->fillRect(option.rect, QColor(0,240,0,128)); + QColor color = option.palette.highlight().color(); + color.setAlpha(128); + painter->fillRect(option.rect, color); } painter->restore(); } diff --git a/modules/gui/src/sequence/seq_selection_painter.hh b/modules/gui/src/sequence_viewer/seq_selection_painter.hh similarity index 96% rename from modules/gui/src/sequence/seq_selection_painter.hh rename to modules/gui/src/sequence_viewer/seq_selection_painter.hh index 416f423c0fc1f187b81cb24f6297821d2fefd7df..a98d5afb6bf0cab9e33e7283ec5e6b80af423aa3 100644 --- a/modules/gui/src/sequence/seq_selection_painter.hh +++ b/modules/gui/src/sequence_viewer/seq_selection_painter.hh @@ -36,6 +36,9 @@ public: SeqSelectionPainter(QObject* parent = 0); void Paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index); +private: + QColor focus_color_; + QColor mouse_over_color_; }; }} diff --git a/modules/gui/src/sequence/seq_text_painter.cc b/modules/gui/src/sequence_viewer/seq_text_painter.cc similarity index 96% rename from modules/gui/src/sequence/seq_text_painter.cc rename to modules/gui/src/sequence_viewer/seq_text_painter.cc index 30c1e162321fc727a516bb14f582f7f8d4797a29..50334bf3909612a58e4945fab049578709cfe54a 100644 --- a/modules/gui/src/sequence/seq_text_painter.cc +++ b/modules/gui/src/sequence_viewer/seq_text_painter.cc @@ -34,7 +34,7 @@ SeqTextPainter::SeqTextPainter(QObject* parent) void SeqTextPainter::Paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index){ painter->save(); - painter->setPen(QPen(Qt::black)); + painter->setPen(index.data(Qt::ForegroundRole).value<QColor>()); QVariant value = index.data(Qt::DisplayRole); if (value.isValid()){ QString text = value.toString(); diff --git a/modules/gui/src/sequence/seq_text_painter.hh b/modules/gui/src/sequence_viewer/seq_text_painter.hh similarity index 100% rename from modules/gui/src/sequence/seq_text_painter.hh rename to modules/gui/src/sequence_viewer/seq_text_painter.hh diff --git a/modules/gui/src/sequence/sequence_delegate.cc b/modules/gui/src/sequence_viewer/sequence_delegate.cc similarity index 100% rename from modules/gui/src/sequence/sequence_delegate.cc rename to modules/gui/src/sequence_viewer/sequence_delegate.cc diff --git a/modules/gui/src/sequence/sequence_delegate.hh b/modules/gui/src/sequence_viewer/sequence_delegate.hh similarity index 100% rename from modules/gui/src/sequence/sequence_delegate.hh rename to modules/gui/src/sequence_viewer/sequence_delegate.hh diff --git a/modules/gui/src/sequence_viewer/sequence_item.cc b/modules/gui/src/sequence_viewer/sequence_item.cc deleted file mode 100644 index 6200f6c15f6ea86c4ee5f970255cb10be60b1f96..0000000000000000000000000000000000000000 --- a/modules/gui/src/sequence_viewer/sequence_item.cc +++ /dev/null @@ -1,494 +0,0 @@ -//------------------------------------------------------------------------------ -// This file is part of the OpenStructure project <www.openstructure.org> -// -// Copyright (C) 2008-2010 by the OpenStructure authors -// -// This library is free software; you can redistribute it and/or modify it under -// the terms of the GNU Lesser General Public License as published by the Free -// Software Foundation; either version 3.0 of the License, or (at your option) -// any later version. -// This library is distributed in the hope that it will be useful, but WITHOUT -// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -// details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this library; if not, write to the Free Software Foundation, Inc., -// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -//------------------------------------------------------------------------------ -/* - Author: Marco Biasini - */ - -#include <ost/mol/mol.hh> -#include <boost/bind.hpp> - -#include "sequence_item.hh" -#include "sequence_scene.hh" - -#include <QPainter> -#include <QGraphicsSceneMouseEvent> -#include <QGraphicsSceneContextMenuEvent> -#include <QGraphicsItem> -#include <QDebug> - -namespace ost { namespace gui { - -using boost::bind; - -Knob::Knob(const QString& text, const QColor& color, - SequenceItem* parent): - QGraphicsItem(parent) -{ - -} - -void Knob::paint(QPainter* painter, const QStyleOptionGraphicsItem*, - QWidget* widget) -{ - painter->setBrush(QBrush(color_)); - painter->setPen(QPen(color_.darker())); - painter->drawEllipse(this->boundingRect()); - if (this->isUnderMouse()) { - painter->setPen(QPen(color_.darker())); - } else { - painter->setPen(QPen(Qt::white)); - } - painter->drawText(this->boundingRect(), Qt::AlignCenter, text_); -} - -QRectF Knob::boundingRect() const -{ - return QRectF(0.0, 0.0, 15.0, 15.0); -} - - -SequenceHeader::SequenceHeader(SequenceItem* parent): - QGraphicsItem(parent) -{ - font_=QFont("Courier", 12); - font_.setKerning(false); - font_.setFixedPitch(true); -} - - -void SequenceHeader::paint(QPainter* painter, const QStyleOptionGraphicsItem*, - QWidget* widget) -{ - SequenceItem* si=dynamic_cast<SequenceItem*>(this->parentItem()); - painter->setFont(font_); - QFontMetrics m(font_); - QString name(si->GetSequence().GetName().c_str()); - QRectF br=this->boundingRect(); - name=m.elidedText(name, Qt::ElideMiddle, br.width()); - painter->drawText(br, Qt::AlignTop, name); -} - -QRectF SequenceHeader::boundingRect() const -{ - QFontMetrics metrics(font_); - SequenceItem* si=dynamic_cast<SequenceItem*>(this->parentItem()); - QString name(si->GetSequence().GetName().c_str()); - QRectF rect(0, -2,name.size()*si->GetCharWidth()*1.1, - si->GetCharHeight()+2); - SequenceScene* s=dynamic_cast<SequenceScene*>(this->scene()); - rect.setWidth(std::min(qreal(s->GetHeaderWidth()), rect.width())); - return rect; -} - -SequenceBody::SequenceBody(SequenceItem* parent): - QGraphicsItem(parent) -{ - -} - - -void SequenceBody::paint(QPainter* painter, const QStyleOptionGraphicsItem*, - QWidget* widget) -{ - SequenceItem* si=dynamic_cast<SequenceItem*>(this->parentItem()); - seq::SequenceHandle seq=si->GetSequence(); - if (!seq.IsValid()) { - return; - } - QString qstr(seq.GetString().c_str()); - QColor sel_color(Qt::yellow); - if (si->IsSecStructureVisible()) { - sel_color.setAlpha(50); - painter->setBrush(QBrush(sel_color)); - painter->setPen(QPen(QColor(Qt::yellow).darker())); - painter->drawPath(si->GetSecStructPaths()); - } - painter->setFont(si->GetFont()); - painter->setPen(QPen(Qt::black)); - QString tt("X"); - QRectF br=this->boundingRect(); - for (int i=0; i<qstr.size(); ++i) { - tt[0]=qstr[i]; - QRectF rect(br.left()+i*si->GetCharWidth(), br.top(), - br.width(), br.height()); - painter->drawText(rect, Qt::AlignLeft|Qt::AlignVCenter, tt); - } - - sel_color=QColor(Qt::green).lighter(); - painter->setPen(QPen(Qt::green)); - sel_color.setAlpha(100); - painter->setBrush(QBrush(sel_color)); - QRectF text_bounds=painter->boundingRect(boundingRect(), - Qt::AlignLeft|Qt::AlignVCenter, - qstr); - const SequenceItem::Selection& sel=si->GetSelection(); - for (size_t i=0; i<sel.size(); ++i) { - painter->drawRect(QRectF(sel[i].Loc*si->GetCharWidth(), 0, - sel[i].Length*si->GetCharWidth(), - si->GetCharHeight())); - } -} - -QRectF SequenceBody::boundingRect() const -{ - SequenceItem* si=dynamic_cast<SequenceItem*>(this->parentItem()); - seq::SequenceHandle seq=si->GetSequence(); - if (!seq.IsValid()) { - return QRectF(); - } - return QRectF(0, -2, seq.GetLength()*si->GetCharWidth(), - si->GetCharHeight()+2); -} - - -SequenceItem::SequenceItem(const seq::SequenceHandle& seq, - QGraphicsItem* parent): - QGraphicsItem(parent), seq_(seq), show_sec_struct_(true) -{ - header_=new SequenceHeader(this); - body_=new SequenceBody(this); - body_->translate(120.0, 0.0); - font_=QFont("Courier", 12); - font_.setKerning(false); - font_.setFixedPitch(true); - QFontMetrics metrics(font_); - advance_=metrics.boundingRect('W').width(); - height_=metrics.boundingRect('|').height(); - ascent_=metrics.ascent(); - this->setAcceptedMouseButtons(Qt::LeftButton); - this->ExtractSecStructSegments(); - selection_change_=false; -} - -SequenceHeader* SequenceItem::GetHeader() -{ - return header_; -} - -SequenceBody* SequenceItem::GetBody() -{ - return body_; -} - -const seq::SequenceHandle& SequenceItem::GetSequence() const -{ - return seq_; -} - -QRectF SequenceItem::GetCharBounds(int pos) const -{ - QPointF a(pos*advance_, 0); - return QRectF(this->mapToScene(a), QSizeF(advance_, height_)); -} - -float SequenceItem::GetCharWidth() const -{ - return advance_; -} - -float SequenceItem::GetCharHeight() const -{ - return height_; -} - -void SequenceItem::paint(QPainter* painter, const QStyleOptionGraphicsItem*, - QWidget* widget) -{ -} - -QRectF SequenceItem::boundingRect() const -{ - QRectF child_r(this->childrenBoundingRect()); - if (show_sec_struct_) { - return QRectF(child_r.topLeft(), - QSize(child_r.width(), child_r.height()*2.5)); - } else { - return QRectF(child_r.topLeft(), - QSize(child_r.width(), child_r.height())); - } -} - -void SequenceItem::ExtractSecStructSegments() -{ - if (!seq_.HasAttachedView()) { - return; - } - mol::ChainView chain=seq_.GetAttachedView().GetChainList()[0]; - sec_=mol::alg::ExtractSecStructureSegments(chain); - this->SecStructSegmentsToPaths(); -} - -void SequenceHeader::contextMenuEvent(QGraphicsSceneContextMenuEvent* event) -{ - //... -} -void SequenceBody::mousePressEvent(QGraphicsSceneMouseEvent* event) -{ - SequenceItem* si=dynamic_cast<SequenceItem*>(this->parentItem()); - event->accept(); - last_index_=-1; - good_ole_click_=true; - merge_select_=event->modifiers() & Qt::ShiftModifier; - si->BeginSelectionChange(); -} - -void SequenceBody::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event) -{ - SequenceItem* si=dynamic_cast<SequenceItem*>(this->parentItem()); - int index=std::max(0, int(event->pos().x()/si->GetCharWidth())); - // find the secondary structure element -- if any that we are in - mol::alg::SecStructureSegments::iterator i=si->GetSecStructSegments().begin(), - e=si->GetSecStructSegments().end(); - for (;i!=e; ++i) { - if (i->first<=index && i->last>=index) { - si->Select(i->first, i->last+1, !merge_select_); - break; - } - } - good_ole_click_=false; -} -void SequenceHeader::mousePressEvent(QGraphicsSceneMouseEvent* event) -{ - event->accept(); -} - -void SequenceHeader::mouseReleaseEvent(QGraphicsSceneMouseEvent* event) -{ - SequenceItem* si=dynamic_cast<SequenceItem*>(this->parentItem()); - if (si->IsEverythingSelected()) { - si->ClearSelection(); - } else { - si->SelectAll(); - } - -} - -void SequenceBody::mouseReleaseEvent(QGraphicsSceneMouseEvent* event) -{ - SequenceItem* si=dynamic_cast<SequenceItem*>(this->parentItem()); - if (good_ole_click_) { - int index=std::max(0, int(event->pos().x()/si->GetCharWidth())); - si->Select(index, index+1, !merge_select_); - } - si->EndSelectionChange(); -} - -void SequenceBody::mouseMoveEvent(QGraphicsSceneMouseEvent* event) -{ - SequenceItem* si=dynamic_cast<SequenceItem*>(this->parentItem()); - good_ole_click_=false; - if (!si->GetSequence().IsValid()) { - return; - } - float x=event->pos().x(); - int index=std::max(0, int(x/si->GetCharWidth())); - if (last_index_!=-1 && last_index_!=index) { - si->Select(last_index_, index, !merge_select_); - } else { - last_index_=index; - } -} - -void SequenceItem::StackToPath(std::vector<QPointF>& stack) -{ - if (!stack.empty()) { - sec_paths_.moveTo(QPointF(stack.front().x(), stack.front().y()+.5*ascent_)); - for (std::vector<QPointF>::iterator j=stack.begin()+1, - e2=stack.end(); j!=e2; ++j) { - sec_paths_.lineTo(QPointF(j->x(), j->y()+0.5*ascent_)); - } - for (std::vector<QPointF>::reverse_iterator j=stack.rbegin(), - e2=stack.rend(); j!=e2; ++j) { - sec_paths_.lineTo(QPointF(j->x(), -j->y()+.5*ascent_)); - } - sec_paths_.closeSubpath(); - stack.clear(); - } -} - -void SequenceItem::SecStructSegmentsToPaths() -{ - sec_paths_=QPainterPath(); - - sec_paths_.setFillRule(Qt::WindingFill); - std::vector<QPointF> stack; - int last_end=-2; - for (mol::alg::SecStructureSegments::iterator i=sec_.begin(), - e=sec_.end(); i!=e; ++i) { - mol::alg::SecStructureSegment s=*i; - if (last_end!=s.first-1) { - this->StackToPath(stack); - } - if (s.ss_type.IsCoil()) { - stack.push_back(QPointF(s.first*advance_, -.6*height_)); - stack.push_back(QPointF((s.last+1)*advance_, -.6*height_)); - } else if (s.ss_type.IsHelical()) { - stack.push_back(QPointF(s.first*advance_, -.6*height_)); - stack.push_back(QPointF(s.first*advance_, -.9*height_)); - stack.push_back(QPointF((s.last+1)*advance_, -.9*height_)); - stack.push_back(QPointF((s.last+1)*advance_, -.6*height_)); - } else if (s.ss_type.IsExtended()) { - stack.push_back(QPointF(s.first*advance_, -.6*height_)); - stack.push_back(QPointF(s.first*advance_, -.9*height_)); - stack.push_back(QPointF((s.last-0.5)*advance_, -.9*height_)); - stack.push_back(QPointF((s.last-0.5)*advance_, -1.3*height_)); - stack.push_back(QPointF((s.last+1)*advance_, -.6*height_)); - - } - last_end=s.last; - } - this->StackToPath(stack); -} - -void SequenceItem::Select(int i1, int i2, bool clear) -{ - if (selection_change_>0) { - selection_=ref_sel_; - } - int a1=std::min(i1, i2); - int len=std::abs(i1-i2); - Range sel_start(a1, len); - Range* sel=&sel_start; - bool modified=false; - if (clear) { - selection_.clear(); - selection_.push_back(*sel); - } else { - for (size_t i=0; i<selection_.size(); ++i) { - if (sel->Loc>=selection_[i].Loc && sel->Loc<selection_[i].End()) { - int old_end=selection_[i].End(); - if (sel->End()<=selection_[i].End()) { - selection_[i].Length=int(sel->Loc-selection_[i].Loc); - if (old_end-sel->End()>0) { - selection_.push_back(Range(sel->End(), old_end-sel->End())); - } - } else { - selection_[i].Length=int(sel->Loc-selection_[i].Loc); - if (sel->End()-old_end>0) { - selection_.push_back(Range(old_end, sel->End()-old_end)); - } - } - modified=true; - break; - } else if (sel->End()>selection_[i].Loc && - sel->End()<=selection_[i].End()) { - int nn=selection_[i].Loc; - selection_[i].Length-=sel->End()-selection_[i].Loc; - selection_[i].Loc=sel->End(); - modified=true; - selection_.push_back(Range(sel->Loc, nn-sel->Loc)); - break; - } else if (sel->Loc<selection_[i].Loc && - sel->End()>selection_[i].End()) { - selection_[i].Length=0; - } else if (sel->Loc==selection_[i].End()) { - selection_[i].Length+=sel->Length; - sel->Length=0; - sel=&selection_[i]; - modified=true; - } else if (sel->End()==selection_[i].Loc) { - selection_[i].Loc-=sel->Length; - selection_[i].Length+=sel->Length; - sel->Length=0; - sel=&selection_[i]; - modified=true; - } - } - if (!modified) { - selection_.push_back(Range(a1, len)); - } - } - Selection::iterator i=std::remove_if(selection_.begin(), selection_.end(), - bind(&Range::Length, _1)==size_t(0)); - selection_.erase(i, selection_.end()); - if (!selection_change_) { - emit this->SelectionChanged(this); - } else { - selection_change_=2; - } - update(); -} - -void SequenceItem::ClearSelection() -{ - selection_.clear(); - if (selection_change_>0) { - selection_change_=2; - } else { - emit this->SelectionChanged(this); - update(); - } -} - -void SequenceItem::SelectAll() -{ - if (!seq_.IsValid()) { - return; - } - selection_.clear(); - selection_.push_back(Range(0, seq_.GetLength())); - if (selection_change_>0) { - selection_change_=1; - } else { - emit this->SelectionChanged(this); - update(); - } -} - -void SequenceItem::BeginSelectionChange() -{ - selection_change_=1; - ref_sel_=selection_; -} - -void SequenceItem::EndSelectionChange() -{ - if (selection_change_==2) { - emit this->SelectionChanged(this); - } - selection_change_=0; -} - -bool SequenceItem::IsEverythingSelected() const -{ - return selection_.size()==1 && selection_.front().Loc==0 && - selection_.front().End()>=static_cast<size_t>(seq_.GetLength()); -} - -const SequenceItem::Selection& SequenceItem::GetSelection() const -{ - return selection_; -} - -mol::alg::SecStructureSegments& SequenceItem::GetSecStructSegments() -{ - return sec_; -} - -void SequenceItem::SetShowSecStructure(bool show) -{ - show_sec_struct_=show; -} - -bool SequenceItem::IsSecStructureVisible() const -{ - return show_sec_struct_; -} - -}} diff --git a/modules/gui/src/sequence_viewer/sequence_item.hh b/modules/gui/src/sequence_viewer/sequence_item.hh deleted file mode 100644 index aeaa63d1a9af36e29a925aa5af3b5fc214b2c8be..0000000000000000000000000000000000000000 --- a/modules/gui/src/sequence_viewer/sequence_item.hh +++ /dev/null @@ -1,153 +0,0 @@ -//------------------------------------------------------------------------------ -// This file is part of the OpenStructure project <www.openstructure.org> -// -// Copyright (C) 2008-2010 by the OpenStructure authors -// -// This library is free software; you can redistribute it and/or modify it under -// the terms of the GNU Lesser General Public License as published by the Free -// Software Foundation; either version 3.0 of the License, or (at your option) -// any later version. -// This library is distributed in the hope that it will be useful, but WITHOUT -// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -// details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this library; if not, write to the Free Software Foundation, Inc., -// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -//------------------------------------------------------------------------------ -#ifndef OST_GUI_SEQUENCE_ITEM_HH -#define OST_GUI_SEQUENCE_ITEM_HH - -#include <ost/gui/module_config.hh> -#include <ost/mol/sec_structure.hh> -#include <ost/mol/alg/sec_structure_segments.hh> - -#include <ost/seq/sequence_handle.hh> - -#include <QGraphicsItem> -#include <QFont> - -namespace ost { namespace gui { - -class SequenceItem; -class SequenceHeader; - -class DLLEXPORT_OST_GUI Knob : public QGraphicsItem { -public: - Knob(const QString& text, const QColor& color, - SequenceItem* parent=NULL); - - virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem* opts, - QWidget* widget=NULL); - virtual QRectF boundingRect() const; -private: - QString text_; - QColor color_; -}; - -class DLLEXPORT_OST_GUI SequenceHeader : public QGraphicsItem { -public: - SequenceHeader(SequenceItem* parent=NULL); - - virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem* opts, - QWidget* widget=NULL); - virtual QRectF boundingRect() const; -protected: - virtual void mousePressEvent(QGraphicsSceneMouseEvent* event); - virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent* event); - virtual void contextMenuEvent(QGraphicsSceneContextMenuEvent* event); -private: - QFont font_; -}; - -class DLLEXPORT_OST_GUI SequenceBody : public QGraphicsItem { -public: - SequenceBody(SequenceItem* parent=NULL); - - virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem* opts, - QWidget* widget=NULL); - virtual QRectF boundingRect() const; -protected: - virtual void mousePressEvent(QGraphicsSceneMouseEvent* event); - virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent* event); - virtual void mouseMoveEvent(QGraphicsSceneMouseEvent* event); - - virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event); -private: - QFont font_; - bool merge_select_; - bool good_ole_click_; - int last_index_; -}; - - -class DLLEXPORT_OST_GUI SequenceItem : public QObject, // required for signals - public QGraphicsItem { - Q_OBJECT -public: - typedef std::vector<Range> Selection; - - SequenceItem(const seq::SequenceHandle& seq, QGraphicsItem* parent=NULL); - - /// \brief get sequence - const seq::SequenceHandle& GetSequence() const; - - virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem* opts, - QWidget* widget=NULL); - virtual QRectF boundingRect() const; - - QRectF GetCharBounds(int pos) const; - - float GetCharWidth() const; - float GetCharHeight() const; - - SequenceBody* GetBody(); - SequenceHeader* GetHeader(); - QPainterPath& GetSecStructPaths() { return sec_paths_; } - QFont GetFont() { return font_; } - - const Selection& GetSelection() const; - void Select(int i1, int i2, bool clear=true); - - void BeginSelectionChange(); - void EndSelectionChange(); - - bool IsEverythingSelected() const; - void ClearSelection(); - void SelectAll(); - void SetShowSecStructure(bool show=true); - bool IsSecStructureVisible() const; - - mol::alg::SecStructureSegments& GetSecStructSegments(); -signals: - - /// \brief emitted whenever the selection changes - /// - /// When using BeginSelectionChange(), no signal is emitted until - /// EndSelectionChange() is called. - void SelectionChanged(SequenceItem* item); -private: - void ExtractSecStructSegments(); - void SecStructSegmentsToPaths(); - void StackToPath(std::vector<QPointF>& stack); - - QPainterPath sec_paths_; - mol::alg::SecStructureSegments sec_; - SequenceHeader* header_; - SequenceBody* body_; - seq::SequenceHandle seq_; - QFont font_; - Selection selection_; - Selection ref_sel_; - float advance_; - float height_; - float ascent_; - int selection_change_; - bool show_sec_struct_; -}; - -typedef std::vector<SequenceItem*> SequenceItemList; -}} - -#endif diff --git a/modules/gui/src/sequence_viewer/sequence_model.cc b/modules/gui/src/sequence_viewer/sequence_model.cc new file mode 100644 index 0000000000000000000000000000000000000000..923a24c0fc2bb2adac5bb72b0be5bf5f21f0862f --- /dev/null +++ b/modules/gui/src/sequence_viewer/sequence_model.cc @@ -0,0 +1,466 @@ +//------------------------------------------------------------------------------ +// This file is part of the OpenStructure project <www.openstructure.org> +// +// Copyright (C) 2008-2010 by the OpenStructure authors +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation; either version 3.0 of the License, or (at your option) +// any later version. +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +//------------------------------------------------------------------------------ + +/* + Author: Stefan Scheuber + */ + +#include <QMap> +#include <QMapIterator> + +#include <QtGui> + +#include "title_row.hh" + +#include "background_painter.hh" +#include "tick_painter.hh" + +#include "sequence_model.hh" + +namespace ost { namespace gui { + +SequenceModel::SequenceModel(QObject *parent) + : QAbstractTableModel(parent), max_columns(0) +{ + this->beginInsertRows(QModelIndex(),this->rowCount(),this->rowCount()); + BaseViewObject* title = new BaseViewObject(this); + TitleRow* title_row = new TitleRow(title); + Painter* p = new BackgroundPainter(title_row); + title_row->InsertPainter(p); + p = new TickPainter(title_row); + title_row->InsertPainter(p); + title->InsertRow(0,title_row); + objects_.append(title); + this->endInsertRows(); +} + +void SequenceModel::InsertSequence(QString& name, seq::SequenceHandle& seq){ + int cols = this->columnCount(); + int new_cols = seq.GetLength(); + this->beginInsertRows(QModelIndex(),this->rowCount(),this->rowCount()); + objects_.append(new SequenceViewObject(seq, name, this)); + if(new_cols > cols){ + this->max_columns = new_cols; + this->beginInsertColumns(QModelIndex(), cols, new_cols); + this->endInsertColumns(); + } + this->endInsertRows(); +} + +void SequenceModel::InsertChain(QString& name, mol::ChainView& view){ + int cols = this->columnCount(); + int new_cols = view.GetResidueCount(); + this->beginInsertRows(QModelIndex(),this->rowCount(),this->rowCount()); + objects_.append(new SequenceViewObject(view, name, this)); + if(new_cols > cols){ + this->max_columns = new_cols; + this->beginInsertColumns(QModelIndex(), cols, new_cols); + this->endInsertColumns(); + } + this->endInsertRows(); +} + +void SequenceModel::InsertAlignment(const seq::AlignmentHandle& alignment){ + int cols = this->columnCount(); + int new_cols = alignment.GetLength(); + this->beginInsertRows(QModelIndex(),this->rowCount(),this->rowCount()+alignment.GetCount()-1); + objects_.append(new AlignmentViewObject(alignment, this)); + if(new_cols > cols){ + this->max_columns = new_cols; + this->beginInsertColumns(QModelIndex(), cols, new_cols); + this->endInsertColumns(); + } + this->endInsertRows(); +} + +void SequenceModel::InsertSequences(const QList<QString>& names, seq::SequenceList& list){ + this->beginInsertRows(this->index(this->rowCount(),0),this->rowCount(),this->rowCount()+list.GetCount()); + objects_.append(new SequenceViewObject(list, names, this)); + this->endInsertRows(); +} + +void SequenceModel::InsertGfxEntity(gfx::EntityP& ent){ + mol::EntityView view=ent->GetView(); + int size = view.GetChainList().size(); + int cols = this->columnCount(); + this->beginInsertRows(QModelIndex(),this->rowCount(),this->rowCount()+size); + SequenceViewObject* obj = new SequenceViewObject(ent, this); + objects_.append(obj); + int new_cols = obj->GetMaxColumnCount(); + if(new_cols > cols){ + this->max_columns = new_cols; + this->beginInsertColumns(QModelIndex(), cols, new_cols); + this->endInsertColumns(); + } + this->endInsertRows(); +} + +void SequenceModel::RemoveGfxEntity(gfx::EntityP& entity){ + if(SequenceViewObject* obj = this->GetItem(entity)){ + int index = this->GetGlobalRow(obj,0); + this->beginRemoveRows(QModelIndex(),index,index+obj->GetRowCount()-1); + int cols_before = this->columnCount(); + objects_.removeOne(obj); + this->endRemoveRows(); + int cols = this->GetColumnCount(); + if(cols_before>cols){ + this->max_columns = cols; + this->beginRemoveColumns(QModelIndex(), cols, cols_before); + this->endRemoveColumns(); + } + } +} + +void SequenceModel::RemoveAlignment(const seq::AlignmentHandle& alignment){ + if(AlignmentViewObject* obj = this->GetItem(alignment)){ + int index = this->GetGlobalRow(obj,0); + this->beginRemoveRows(QModelIndex(),index,index+obj->GetRowCount()-1); + int cols_before = this->columnCount(); + objects_.removeOne(obj); + this->endRemoveRows(); + int cols = this->GetColumnCount(); + if(cols_before>cols){ + this->max_columns = cols; + this->beginRemoveColumns(QModelIndex(), cols, cols_before); + this->endRemoveColumns(); + } + } +} + +int SequenceModel::GetColumnCount() const{ + int cols = 0; + for(int i = 0; i<objects_.size();i++){ + int ob_cols = objects_[i]->GetMaxColumnCount(); + if(ob_cols>cols){ + cols = ob_cols; + } + } + return cols; +} + +SequenceViewObject* SequenceModel::GetItem(const gfx::EntityP& entity){ + if(entity != NULL){ + for (int i = 0 ; i< objects_.size(); i++){ + if(SequenceViewObject* seq_view_object = qobject_cast<SequenceViewObject*>(objects_[i])){ + if(entity == seq_view_object->GetGfxObject()){ + return seq_view_object; + } + } + } + } + return NULL; +} + +AlignmentViewObject* SequenceModel::GetItem(const seq::AlignmentHandle& alignment){ + for (int i = 0 ; i< objects_.size(); i++){ + if(AlignmentViewObject* alignment_object = qobject_cast<AlignmentViewObject*>(objects_[i])){ + if(alignment == alignment_object->GetAlignment()){ + return alignment_object; + } + } + } + return NULL; +} + +const PainterList& SequenceModel::GetPainters(const QModelIndex& index) const{ + QPair<int, BaseViewObject*> pair = this->GetRowWithItem(index); + if(pair.second){ + return pair.second->GetRow(pair.first)->GetPainters(); + } + return empty_painter_list_; +} + +QPair<int, BaseViewObject*> SequenceModel::GetRowWithItem(int row) const{ + if(!objects_.isEmpty()){ + int rows = 0; + int i = -1; + int last_row = 0; + while (rows <= row && i < objects_.size()){ + i++; + last_row =objects_[i]->GetRowCount(); + rows += last_row; + } + int sub_index = row - (rows-last_row); + return QPair<int, BaseViewObject*>(sub_index, objects_[i]); + } + return QPair<int, BaseViewObject*>(-1, NULL); +} + +QPair<int, BaseViewObject*> SequenceModel::GetRowWithItem(const QModelIndex& index) const{ + return this->GetRowWithItem(index.row()); +} + +BaseViewObject* SequenceModel::GetItem(const QModelIndex& index) const +{ + return this->GetRowWithItem(index).second; +} + +int SequenceModel::GetGlobalRow(BaseViewObject* obj, int row) const +{ + int glob_row = -1; + int index = objects_.indexOf(obj); + if(index >= 0){ + glob_row = 0; + for(int i=0; i<index; i++){ + glob_row += objects_[i]->GetRowCount(); + } + return glob_row + row; + } + return glob_row; +} + +QModelIndexList SequenceModel::GetModelIndexes(gfx::EntityP& entity, const mol::EntityView& view) +{ + QModelIndexList list; + if(BaseViewObject* object = this->GetItem(entity)){ + if(SequenceViewObject* seq_view_object = qobject_cast<SequenceViewObject*>(object)){ + QMap<int, QList<int> > indexes = seq_view_object->GetIndexesForView(view); + QMapIterator< int, QList<int> > i(indexes); + while (i.hasNext()) { + i.next(); + int row = this->GetGlobalRow(seq_view_object, i.key()); + const QList<int>& index_list = i.value(); + for(int i=0; i<index_list.size(); i++){ + list.append(this->index(row,index_list[i])); + } + } + } + } + return list; +} + +QModelIndexList SequenceModel::GetModelIndexes(const QString& subject, const QString& sequence_name) +{ + QModelIndexList list; + for (int i = 0; i<objects_.size(); i++){ + if(SequenceViewObject* seq_view_object = qobject_cast<SequenceViewObject*>(objects_[i])){ + QMap<int, QList<int> > indexes = seq_view_object->GetIndexesForSubject(subject,sequence_name); + QMapIterator< int, QList<int> > iter(indexes); + while (iter.hasNext()) { + iter.next(); + int row = this->GetGlobalRow(seq_view_object, iter.key()); + const QList<int>& index_list = iter.value(); + for(int j=0; j<index_list.size(); j++){ + list.append(this->index(row,index_list[j])); + } + } + } + } + return list; +} + +void SequenceModel::SelectionChanged(const QItemSelection& sel, const QItemSelection& desel) +{ + QMap<int,QPair<QSet<int>,QSet<int> > > sel_map; + const QModelIndexList& sel_indexes = sel.indexes(); + for(int i =0; i< sel_indexes.size(); i++){ + sel_map[sel_indexes[i].row()].first.insert(sel_indexes[i].column()); + } + + const QModelIndexList& desel_indexes = desel.indexes(); + for(int i =0; i< desel_indexes.size(); i++){ + sel_map[desel_indexes[i].row()].second.insert(desel_indexes[i].column()); + } + + QMapIterator< int,QPair<QSet<int>,QSet<int> > > i(sel_map); + while (i.hasNext()) { + i.next(); + QPair<int, BaseViewObject*> item = this->GetRowWithItem(i.key()); + item.second->SetSelection(item.first,i.value().first, i.value().second); + } +} + +void SequenceModel::DoubleClicked(const QModelIndex& index) +{ + QPair<int, BaseViewObject*> item = this->GetRowWithItem(index); + if(item.second){ + item.second->DoubleClicked(item.first,index.column()); + } +} + +const QStringList& SequenceModel::GetDisplayModes() +{ + display_modes_.clear(); + QMap<QString,int> string_map; + for (int i = 0; i<objects_.size(); i++){ + const QStringList& list = objects_[i]->GetDisplayModes(); + for(int j=0; j<list.size(); j++){ + if(!string_map.contains(list.at(j))){ + string_map.insert(list.at(j),1); + } + else { + string_map[list.at(j)] = string_map[list.at(j)] + 1; + } + } + } + bool removed = false; + QMapIterator<QString, int> i(string_map); + while (i.hasNext()) { + i.next(); + if(objects_.size()-1 <= i.value()){ + display_modes_.append(i.key()); + } + else{ + removed = true; + } + } + if(removed){ + display_modes_.insert(0," "); + } + return display_modes_; +} + +const QStringList& SequenceModel::GetDisplayModes(const gfx::EntityP& entity) +{ + BaseViewObject* item = this->GetItem(entity); + if(item){ + return item->GetDisplayModes(); + } + else{ + return empty_string_list_; + } +} + +const QStringList& SequenceModel::GetDisplayModes(const seq::AlignmentHandle& alignment) +{ + BaseViewObject* item = this->GetItem(alignment); + if(item){ + return item->GetDisplayModes(); + } + else{ + return empty_string_list_; + } +} + +const QString& SequenceModel::GetCurrentDisplayMode() +{ + current_display_mode_.clear(); + for (int i = 0; i<objects_.size(); i++){ + const QString& mode = objects_[i]->GetCurrentDisplayMode(); + if(current_display_mode_.isEmpty()){ + current_display_mode_ = mode; + } + else if(current_display_mode_ != mode){ + current_display_mode_ = " "; + break; + } + } + return current_display_mode_; +} + +const QString& SequenceModel::GetCurrentDisplayMode(const gfx::EntityP& entity) +{ + BaseViewObject* item = this->GetItem(entity); + if(item){ + return item->GetCurrentDisplayMode(); + } + else{ + return empty_string_; + } +} + +const QString& SequenceModel::GetCurrentDisplayMode(const seq::AlignmentHandle& alignment) +{ + BaseViewObject* item = this->GetItem(alignment); + if(item){ + return item->GetCurrentDisplayMode(); + } + else{ + return empty_string_; + } +} + +void SequenceModel::SetDisplayMode(const QString& mode) +{ + for (int i = 0; i<objects_.size(); i++){ + objects_[i]->SetDisplayMode(mode); + } +} + +void SequenceModel::SetDisplayMode(const gfx::EntityP& entity, const QString& mode) +{ + BaseViewObject* item = this->GetItem(entity); + if(item){ + return item->SetDisplayMode(mode); + } +} + +void SequenceModel::SetDisplayMode(const seq::AlignmentHandle& alignment, const QString& mode) +{ + BaseViewObject* item = this->GetItem(alignment); + if(item){ + return item->SetDisplayMode(mode); + } +} + +int SequenceModel::rowCount(const QModelIndex& parent) const +{ + int rows = 0; + for (int i = 0; i<objects_.size(); i++){ + rows += objects_[i]->GetRowCount(); + } + return rows; +} + +int SequenceModel::columnCount(const QModelIndex& parent) const +{ + return max_columns; +} + +QVariant SequenceModel::data(const QModelIndex& index, int role) const +{ + QPair<int, BaseViewObject*> item = this->GetRowWithItem(index); + if(!item.second) return QVariant(); + QVariant data = item.second->GetData(item.first,index.column(),role); + return data; +} + +QVariant SequenceModel::headerData(int section, Qt::Orientation orientation, + int role) const +{ + if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { + return QVariant(""); + } + return QVariant(); +} + +Qt::ItemFlags SequenceModel::flags(const QModelIndex& index) const +{ + QPair<int, BaseViewObject*> item = GetRowWithItem(index); + if(item.second){ + return item.second->Flags(item.first, index.column()); + } + return QAbstractItemModel::flags(index); +} + +void SequenceModel::ZoomIn() +{ + for (int i = 0; i<objects_.size(); i++){ + objects_[i]->ZoomIn(); + } +} + +void SequenceModel::ZoomOut() +{ + for (int i = 0; i<objects_.size(); i++){ + objects_[i]->ZoomOut(); + } +} + +}} diff --git a/modules/gui/src/sequence/sequence_model.hh b/modules/gui/src/sequence_viewer/sequence_model.hh similarity index 61% rename from modules/gui/src/sequence/sequence_model.hh rename to modules/gui/src/sequence_viewer/sequence_model.hh index 50618db9c0a8bc6054dc5ac3ff3d015b5b011c1b..d0afbbc4d8d8f7d5ed192d9ee6cab239f753fbaf 100644 --- a/modules/gui/src/sequence/sequence_model.hh +++ b/modules/gui/src/sequence_viewer/sequence_model.hh @@ -29,9 +29,13 @@ #include <ost/mol/chain_view.hh> #include <ost/seq/sequence_list.hh> +#include <ost/seq/alignment_handle.hh> -#include "sequence_model.hh" -#include "view_object.hh" +#include <ost/gfx/entity.hh> + +#include "base_view_object.hh" +#include "alignment_view_object.hh" +#include "sequence_view_object.hh" namespace ost { namespace gui { @@ -42,16 +46,30 @@ class SequenceModel : public QAbstractTableModel public: SequenceModel(QObject *parent = 0); + void InsertAlignment(const seq::AlignmentHandle& alignment); void InsertGfxEntity(gfx::EntityP& entity); void InsertChain(QString& name, mol::ChainView& view); void InsertSequence(QString& name, seq::SequenceHandle& seq); void InsertSequences(const QList<QString>& names, seq::SequenceList& list); + void RemoveAlignment(const seq::AlignmentHandle& alignment); void RemoveGfxEntity(gfx::EntityP& entity); QModelIndexList GetModelIndexes(gfx::EntityP& entity, const mol::EntityView& view); - int GetGlobalRow(ViewObject* obj, int row) const; + QModelIndexList GetModelIndexes(const QString& subject, const QString& sequence_name=QString()); + + int GetGlobalRow(BaseViewObject* obj, int row) const; + + const QStringList& GetDisplayModes(); + const QStringList& GetDisplayModes(const gfx::EntityP& entity); + const QStringList& GetDisplayModes(const seq::AlignmentHandle& alignment); + const QString& GetCurrentDisplayMode(); + const QString& GetCurrentDisplayMode(const gfx::EntityP& entity); + const QString& GetCurrentDisplayMode(const seq::AlignmentHandle& alignment); + void SetDisplayMode(const QString& mode); + void SetDisplayMode(const gfx::EntityP& entity, const QString& mode); + void SetDisplayMode(const seq::AlignmentHandle& alignment, const QString& mode); const PainterList& GetPainters(const QModelIndex& index) const; @@ -72,15 +90,21 @@ public slots: void ZoomOut(); void DoubleClicked(const QModelIndex& index); void SelectionChanged(const QItemSelection& sel, const QItemSelection& desel); - private: - ViewObject* GetItem(gfx::EntityP& entity); - ViewObject* GetItem(const QModelIndex& index) const; - QPair<int, ViewObject*> GetRowWithItem(int row) const; - QPair<int, ViewObject*> GetRowWithItem(const QModelIndex& index) const; - - QList<ViewObject*> objects_; + int GetColumnCount() const; + SequenceViewObject* GetItem(const gfx::EntityP& entity); + AlignmentViewObject* GetItem(const seq::AlignmentHandle& alignment); + BaseViewObject* GetItem(const QModelIndex& index) const; + QPair<int, BaseViewObject*> GetRowWithItem(int row) const; + QPair<int, BaseViewObject*> GetRowWithItem(const QModelIndex& index) const; + + QList<BaseViewObject*> objects_; int max_columns; + PainterList empty_painter_list_; + QString empty_string_; + QStringList empty_string_list_; + QStringList display_modes_; + QString current_display_mode_; }; diff --git a/modules/gui/src/sequence/sequence_row.cc b/modules/gui/src/sequence_viewer/sequence_row.cc similarity index 82% rename from modules/gui/src/sequence/sequence_row.cc rename to modules/gui/src/sequence_viewer/sequence_row.cc index b9f758053613d533897cf9f4b19092536259761f..f614799f1d14fa71b95dd8b05d2eb15845889fbb 100644 --- a/modules/gui/src/sequence/sequence_row.cc +++ b/modules/gui/src/sequence_viewer/sequence_row.cc @@ -29,16 +29,22 @@ #include <ost/gfx/entity.hh> -#include "view_object.hh" +#include "sequence_view_object.hh" #include "sequence_row.hh" namespace ost { namespace gui { -SequenceRow::SequenceRow(const QString& name, seq::SequenceHandle& sequence, ViewObject* parent) : BaseRow(QFont("Courier",11),parent), name_(name), name_font_(QFont("Courier",11)), sequence_(sequence) -{ } +SequenceRow::SequenceRow(const QString& name, seq::SequenceHandle& sequence, SequenceViewObject* parent) : BaseRow(QFont("Courier",11),parent), name_(name), name_font_(QFont("Courier",11)), sequence_(sequence) +{ + name_font_.setBold(true); + name_font_.setItalic(true); +} -SequenceRow::SequenceRow(const QString& name, ViewObject* parent) : BaseRow(QFont("Courier",11),parent), name_(name) -{ } +SequenceRow::SequenceRow(const QString& name, SequenceViewObject* parent) : BaseRow(QFont("Courier",11),parent), name_(name), name_font_(QFont("Courier",11)) +{ + name_font_.setBold(true); + name_font_.setItalic(true); +} int SequenceRow::GetColumnCount() const { @@ -69,12 +75,22 @@ QVariant SequenceRow::GetData(int column, int role) const { if(column<0 || column > sequence_.GetLength())return QVariant(); + if (role == Qt::ForegroundRole){ + return QColor(Qt::black); + } + if(column == 0) { if (role == Qt::DisplayRole){ return QVariant(this->name_); } if (role == Qt::FontRole){ - return QVariant(name_font_); + return QVariant(this->name_font_); + } + if (role == Qt::TextAlignmentRole){ + return QVariant(Qt::AlignLeft|Qt::AlignVCenter); + } + if (role==Qt::ToolTipRole){ + return QVariant(this->name_); } } else if(column > 0) { @@ -96,7 +112,7 @@ QVariant SequenceRow::GetData(int column, int role) const Qt::ItemFlags SequenceRow::Flags(int column) const { - if(column<0 || column > this->GetColumnCount())return Qt::NoItemFlags; + if(column<0 || column >= this->GetColumnCount())return Qt::NoItemFlags; if(column==0){ return Qt::ItemIsSelectable|Qt::ItemIsEnabled; @@ -119,7 +135,7 @@ void SequenceRow::DoubleClicked(int column) void SequenceRow::SetSelection(const QSet<int>& added, const QSet<int>& removed) { - ViewObject* view_object = qobject_cast<ViewObject*>(this->parent()); + SequenceViewObject* view_object = qobject_cast<SequenceViewObject*>(this->parent()); if(view_object){ if(gfx::EntityP entity = view_object->GetGfxObject()){ mol::EntityView sel = entity->GetSelection(); diff --git a/modules/gui/src/sequence/sequence_row.hh b/modules/gui/src/sequence_viewer/sequence_row.hh similarity index 90% rename from modules/gui/src/sequence/sequence_row.hh rename to modules/gui/src/sequence_viewer/sequence_row.hh index 58c0a2dad280d19e36f2f00808998646677a613a..51979f330de1a0c2249816c6eda26784d3f29564 100644 --- a/modules/gui/src/sequence/sequence_row.hh +++ b/modules/gui/src/sequence_viewer/sequence_row.hh @@ -31,15 +31,15 @@ namespace ost { namespace gui { -class ViewObject; +class SequenceViewObject; class SequenceRow : public BaseRow { Q_OBJECT public: - SequenceRow(const QString& name, seq::SequenceHandle& sequence, ViewObject* parent); - SequenceRow(const QString& name, ViewObject* parent); + SequenceRow(const QString& name, seq::SequenceHandle& sequence, SequenceViewObject* parent); + SequenceRow(const QString& name, SequenceViewObject* parent); virtual int GetColumnCount() const; @@ -53,7 +53,7 @@ public: virtual void SetSequence(seq::SequenceHandle& sequence); const seq::SequenceHandle& GetSequence() const; - void SetSelection(const QSet<int>& added, const QSet<int>& removed); + virtual void SetSelection(const QSet<int>& added, const QSet<int>& removed); private: QString name_; diff --git a/modules/gui/src/sequence_viewer/sequence_scene.cc b/modules/gui/src/sequence_viewer/sequence_scene.cc deleted file mode 100644 index 4b77a71e3e61d610ecfa973a87ae242be634d3d2..0000000000000000000000000000000000000000 --- a/modules/gui/src/sequence_viewer/sequence_scene.cc +++ /dev/null @@ -1,134 +0,0 @@ -//------------------------------------------------------------------------------ -// This file is part of the OpenStructure project <www.openstructure.org> -// -// Copyright (C) 2008-2010 by the OpenStructure authors -// -// This library is free software; you can redistribute it and/or modify it under -// the terms of the GNU Lesser General Public License as published by the Free -// Software Foundation; either version 3.0 of the License, or (at your option) -// any later version. -// This library is distributed in the hope that it will be useful, but WITHOUT -// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -// details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this library; if not, write to the Free Software Foundation, Inc., -// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -//------------------------------------------------------------------------------ -#include "sequence_scene.hh" -#include <boost/bind.hpp> -#include <QPainter> - -namespace ost { namespace gui { - -using boost::bind; - -void SequenceScene::drawBackground(QPainter* painter, const QRectF& rect) -{ - if (sequences_.empty()) { - return; - } - QBrush stripe_brushes[]={ - QBrush(QColor(Qt::white)), - QBrush(QColor(245, 245, 245)) - }; - float width=sequences_[0]->GetCharWidth()*5; - QRectF stripe(QPointF(((int(rect.left()/width)-1)-1)*width+header_width_, - rect.top()), - QSizeF(width, rect.height())); - int n=round(rect.width()/width)+2; - int start=std::max(0, int(floor(rect.left()/width)))-1; - for (int i=0; i<n; ++i, stripe.translate(width, 0.0)) { - painter->fillRect(stripe, stripe_brushes[(i+start+2) % 2]); - } - painter->setPen(QPen(Qt::gray)); - const static int STEP_SIZE=10; - float s=sequences_[0]->GetCharWidth()*STEP_SIZE; - int n_rulers=round(rect.width()/s); - int first=std::max(0, int(floor(rect.left()/s))); - painter->fillRect(QRectF(QPointF(0.0, rect.top()), - QSizeF(header_width_, rect.height())), - QBrush(Qt::white)); - for (int i=first;i<first+n_rulers+2; ++i) { - painter->drawText(QRectF(QPointF(i*s-50+header_width_, - rect.top()), QSizeF(100, 30)), - Qt::AlignCenter, QString::number(i*STEP_SIZE)); - painter->drawLine(QPointF(i*s+header_width_, rect.top()+30), - QPointF(i*s+header_width_, rect.top()+30+rect.height())); - } - -} - -void SequenceScene::SetContextMenu(QMenu* menu) -{ - context_menu_=menu; -} - -QMenu* SequenceScene::GetContextMenu() -{ - return context_menu_; -} - -SequenceScene::SequenceScene(QObject* parent): - QGraphicsScene(parent), header_width_(120.0) -{ - connect(this, SIGNAL(sceneRectChanged(const QRectF&)), this, - SLOT(OnSceneRectChange(const QRectF&))); - context_menu_=NULL; -} - -void SequenceScene::RepackSequences() -{ - if (sequences_.empty()) { - return; - } - sequences_.front()->setPos(0.0, 50.0); - for (std::vector<SequenceItem*>::iterator i=sequences_.begin()+1, - e=sequences_.end(); i!=e; ++i) { - (*i)->setPos(0.0, (*(i-1))->pos().y()+ - (*(i-1))->boundingRect().height()); - } -} - -void SequenceScene::AddSequence(SequenceItem* seq) -{ - this->addItem(seq); - if (!sequences_.empty()) { - seq->setPos(0.0, sequences_.back()->pos().y()+ - sequences_.back()->boundingRect().height()); - } else { - seq->setPos(0.0, 50.0); - } - sequences_.push_back(seq); - update(); -} - -void SequenceScene::RemoveSequence(SequenceItem* seq) -{ - this->removeItem(seq); - std::vector<SequenceItem*>::iterator f=std::find(sequences_.begin(), - sequences_.end(), seq); - if(f != sequences_.end()) - { - sequences_.erase(f); - } - RepackSequences(); -} - -void SequenceScene::SetHeaderWidth(float width) -{ - header_width_=width; - update(); -} - -float SequenceScene:: GetHeaderWidth() const -{ - return header_width_; -} - -void SequenceScene::OnSceneRectChange(const QRectF& rect) -{ -} - -}} diff --git a/modules/gui/src/sequence_viewer/sequence_scene.hh b/modules/gui/src/sequence_viewer/sequence_scene.hh deleted file mode 100644 index 2547d9fbdf27527b2870617058affc08c9e76b2e..0000000000000000000000000000000000000000 --- a/modules/gui/src/sequence_viewer/sequence_scene.hh +++ /dev/null @@ -1,67 +0,0 @@ -//------------------------------------------------------------------------------ -// This file is part of the OpenStructure project <www.openstructure.org> -// -// Copyright (C) 2008-2010 by the OpenStructure authors -// -// This library is free software; you can redistribute it and/or modify it under -// the terms of the GNU Lesser General Public License as published by the Free -// Software Foundation; either version 3.0 of the License, or (at your option) -// any later version. -// This library is distributed in the hope that it will be useful, but WITHOUT -// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -// details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this library; if not, write to the Free Software Foundation, Inc., -// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -//------------------------------------------------------------------------------ -#ifndef OST_GUI_SEQUENCE_SCENE_HH -#define OST_GUI_SEQUENCE_SCENE_HH - -#include <ost/gui/module_config.hh> -#include <ost/gui/sequence_viewer/sequence_item.hh> - -#include <QGraphicsScene> - -namespace ost { namespace gui { - - -class SequenceScene : public QGraphicsScene { - Q_OBJECT -public: - typedef std::vector<Range> Selection; - - SequenceScene(QObject* parent=NULL); - - void SetContextMenu(QMenu* menu); - - QMenu* GetContextMenu(); - std::vector<SequenceItem*>& GetSequences() { return sequences_; } - const Selection& GetSelection() const; - - /// \brief get length of longest sequence (including gaps) in the alignment - void GetMaxSequenceLength(); - - - void SetHeaderWidth(float width); - float GetHeaderWidth() const; - void AddSequence(SequenceItem* seq); - void RemoveSequence(SequenceItem* seq); - void RepackSequences(); -public slots: - void OnSceneRectChange(const QRectF& rect); -protected: - virtual void drawBackground(QPainter* painter, const QRectF& rect); -private: - void UpdateAlignment(); - Selection selection_; - Selection ref_sel_; - std::vector<SequenceItem*> sequences_; - QMenu* context_menu_; - float header_width_; -}; - -}} - -#endif diff --git a/modules/gui/src/sequence_viewer/sequence_search_bar.cc b/modules/gui/src/sequence_viewer/sequence_search_bar.cc index 808d45904e21293e5360e7bd5e3e8e25de82c132..9ae88675e2468dbe5083cbb642df653fd563c67a 100644 --- a/modules/gui/src/sequence_viewer/sequence_search_bar.cc +++ b/modules/gui/src/sequence_viewer/sequence_search_bar.cc @@ -21,7 +21,6 @@ */ #include "sequence_search_bar.hh" -#include "sequence_item.hh" #include <QHBoxLayout> #include <QLineEdit> @@ -32,7 +31,7 @@ namespace ost { namespace gui { -SequenceSearchBar::SequenceSearchBar(QWidget* parent): +SeqSearchBar::SeqSearchBar(QWidget* parent): QWidget(parent) { subject_=new QLineEdit(this); @@ -41,13 +40,13 @@ SequenceSearchBar::SequenceSearchBar(QWidget* parent): QHBoxLayout* l= new QHBoxLayout(this); l->addSpacing(2); l->addWidget(subject_, 0); + l->setStretch(0,1); l->addWidget(search_all_, 0); QLabel* label=new QLabel("search in:", this); l->addSpacing(10); l->addWidget(label, 0); l->addWidget(search_in_, 0); - l->addStretch(1); - subject_->setMaximumWidth(200); + //subject_->setMaximumWidth(200); setLayout(l); l->setSizeConstraint(QLayout::SetMaximumSize); l->setMargin(1); @@ -67,23 +66,22 @@ SequenceSearchBar::SequenceSearchBar(QWidget* parent): SLOT(OnSearchInChanged(int))); } -void SequenceSearchBar::Show(const std::vector<SequenceItem*>& sequences) +void SeqSearchBar::UpdateItems(const QStringList& sequences) { search_in_->clear(); - - for (size_t i=0;i<sequences.size(); ++i) { - QString name(sequences[i]->GetSequence().GetName().c_str()); - search_in_->addItem(name); + + for(int i=0;i< sequences.size(); i++){ + search_in_->addItem(sequences[i]); } + if (sequences.empty()) { search_all_->setCheckState(Qt::Checked); search_in_->setEnabled(false); } - this->show(); subject_->setFocus(Qt::ActiveWindowFocusReason); subject_->selectAll(); } -void SequenceSearchBar::OnSearchAllChanged(int state) +void SeqSearchBar::OnSearchAllChanged(int state) { if (state==Qt::Unchecked) { search_in_->setEnabled(true); @@ -91,22 +89,22 @@ void SequenceSearchBar::OnSearchAllChanged(int state) search_in_->setEnabled(false); } emit Changed(subject_->text(), search_all_->checkState()==Qt::Checked, - search_in_->currentIndex()); + search_in_->currentText()); } -void SequenceSearchBar::OnSearchInChanged(int index) +void SeqSearchBar::OnSearchInChanged(int index) { emit Changed(subject_->text(), search_all_->checkState()==Qt::Checked, - search_in_->currentIndex()); + search_in_->currentText()); } -void SequenceSearchBar::OnSubjectChanged(const QString& str) +void SeqSearchBar::OnSubjectChanged(const QString& str) { emit Changed(str, search_all_->checkState()==Qt::Checked, - search_in_->currentIndex()); + search_in_->currentText()); } -void SequenceSearchBar::paintEvent(QPaintEvent* paint_event) +void SeqSearchBar::paintEvent(QPaintEvent* paint_event) { QPainter p(this); p.setBrush(QBrush(QColor(Qt::blue).lighter(300))); @@ -115,7 +113,7 @@ void SequenceSearchBar::paintEvent(QPaintEvent* paint_event) paint_event->accept(); } -void SequenceSearchBar::keyPressEvent(QKeyEvent* key_event) +void SeqSearchBar::keyPressEvent(QKeyEvent* key_event) { if (key_event->key()==Qt::Key_Escape) { this->hide(); diff --git a/modules/gui/src/sequence_viewer/sequence_search_bar.hh b/modules/gui/src/sequence_viewer/sequence_search_bar.hh index fae7280dc6d119f47063e29645a5baaa882c95fe..865a42be22c30a828ba24285319f8f6d5bb592cc 100644 --- a/modules/gui/src/sequence_viewer/sequence_search_bar.hh +++ b/modules/gui/src/sequence_viewer/sequence_search_bar.hh @@ -16,8 +16,8 @@ // along with this library; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA //------------------------------------------------------------------------------ -#ifndef OST_SEQUENCE_SEARCH_BAR_HH -#define OST_SEQUENCE_SEARCH_BAR_HH +#ifndef OST_SEQUENCE_VIEWER_SEQUENCE_SEARCH_BAR_HH +#define OST_SEQUENCE_VIEWER_SEQUENCE_SEARCH_BAR_HH /* Author: Marco Biasini @@ -27,20 +27,19 @@ #include <QWidget> #include <QComboBox> #include <QCheckBox> +#include <QSet> namespace ost { namespace gui { -class SequenceItem; - /// \brief search bar to search in multiple sequence alignment -class DLLEXPORT_OST_GUI SequenceSearchBar : public QWidget { +class DLLEXPORT_OST_GUI SeqSearchBar : public QWidget { Q_OBJECT public: - SequenceSearchBar(QWidget* parent=NULL); + SeqSearchBar(QWidget* parent=NULL); - void Show(const std::vector<SequenceItem*>& sequences); + void UpdateItems(const QStringList& sequences); signals: - void Changed(const QString&, bool, int); + void Changed(const QString&, bool, const QString&); public slots: void OnSubjectChanged(const QString&); void OnSearchInChanged(int); diff --git a/modules/gui/src/sequence/sequence_table_view.cc b/modules/gui/src/sequence_viewer/sequence_table_view.cc similarity index 87% rename from modules/gui/src/sequence/sequence_table_view.cc rename to modules/gui/src/sequence_viewer/sequence_table_view.cc index 2152c1a6bb6b129e27b579d54ffc0560b036ee5f..807c130da835bf75bcb219073a9ea704d7faf5e3 100644 --- a/modules/gui/src/sequence/sequence_table_view.cc +++ b/modules/gui/src/sequence_viewer/sequence_table_view.cc @@ -66,11 +66,14 @@ SequenceTableView::SequenceTableView(QAbstractItemModel * model) delegate_ = new SequenceDelegate(qobject_cast<SequenceModel*>(this->model()),this); +#if !(defined(__APPLE__) && (QT_VERSION>=0x040600)) this->InitStaticRow(); this->InitStaticColumn(); -// this->viewport()->stackUnder(static_row_); this->InitStaticField(); -// this->viewport()->stackUnder(static_field_); + this->viewport()->stackUnder(static_field_); + this->viewport()->stackUnder(static_column_); + this->viewport()->stackUnder(static_row_); +#endif } void SequenceTableView::InitStaticColumn() @@ -82,7 +85,6 @@ void SequenceTableView::InitStaticColumn() static_column_->verticalHeader()->hide(); static_column_->horizontalHeader()->hide(); - //this->viewport()->stackUnder(static_column_); static_column_->setSelectionBehavior(SelectRows); static_column_->setSelectionModel(this->selectionModel()); for(int col=1; col<this->model()->columnCount(); col++){ @@ -95,8 +97,9 @@ void SequenceTableView::InitStaticColumn() static_column_->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); static_column_->show(); static_column_->setStyleSheet("QTableView { border: 0px;" - "background-color: #F6F6F6;" - "selection-background-color: #EEEEEE}" + "selection-color: #4f4f4f;" + "selection-background-color: white;" + "background-color: white}" "QTableView::item{ border: none;" "padding: 0px; border-width: 0px; margin: 0px;}"); static_column_->setShowGrid(false); @@ -130,8 +133,7 @@ void SequenceTableView::InitStaticRow() static_row_->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); static_row_->show(); static_row_->setStyleSheet("QTableView { border: 0px;" - "background-color: #F6F6F6;" - "selection-background-color: #EEEEEE}" + "background-color: #FFFFFF}" "QTableView::item{ border: none;" "padding: 0px; border-width: 0px; margin: 0px;}"); static_row_->setShowGrid(false); @@ -169,8 +171,9 @@ void SequenceTableView::InitStaticField(){ static_field_->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); static_field_->show(); static_field_->setStyleSheet("QTableView { border: 0px;" - "background-color: #E0E0E0;" - "selection-background-color: #EEEEEE}" + "selection-color: transparent;" + "selection-background-color: transparent;" + "background-color: white}" "QTableView::item{ border: none;" "padding: 0px; border-width: 0px; margin: 0px;}"); static_field_->setShowGrid(false); @@ -186,7 +189,8 @@ void SequenceTableView::InitStaticField(){ this->updateStaticField(); } void SequenceTableView::ResizeWidth(int index, int, int size) -{ +{ +#if !(defined(__APPLE__) && (QT_VERSION>=0x040600)) if(index == 0){ static_column_->setColumnWidth(0,size); static_field_->setColumnWidth(0,size); @@ -194,10 +198,12 @@ void SequenceTableView::ResizeWidth(int index, int, int size) this->updateStaticField(); } static_row_->setRowHeight(index,size); +#endif } void SequenceTableView::ResizeHeight(int index, int, int size) { +#if !(defined(__APPLE__) && (QT_VERSION>=0x040600)) static_column_->setRowHeight(index, size); if(index == 0){ static_row_->setRowHeight(0,size); @@ -205,14 +211,17 @@ void SequenceTableView::ResizeHeight(int index, int, int size) this->updateStaticRow(); this->updateStaticField(); } +#endif } void SequenceTableView::resizeEvent(QResizeEvent * event) { QTableView::resizeEvent(event); +#if !(defined(__APPLE__) && (QT_VERSION>=0x040600)) this->updateStaticColumn(); this->updateStaticRow(); this->updateStaticField(); +#endif } QModelIndex SequenceTableView::moveCursor(CursorAction action, Qt::KeyboardModifiers modifiers) @@ -236,9 +245,13 @@ QModelIndex SequenceTableView::moveCursor(CursorAction action, Qt::KeyboardModif } void SequenceTableView::scrollTo(const QModelIndex & index, ScrollHint hint){ +#if !(defined(__APPLE__) && (QT_VERSION>=0x040600)) if(index.column()>0 && index.row()>0){ QTableView::scrollTo(index, hint); } +#else + QTableView::scrollTo(index, hint); +#endif } void SequenceTableView::updateStaticColumn() @@ -267,18 +280,23 @@ void SequenceTableView::updateStaticField(){ } void SequenceTableView::columnCountChanged(const QModelIndex& index, int old_count, int new_count){ - if(old_count >= 0 && old_count <= new_count){ + if(old_count >= 0 && old_count <= new_count) { + if(old_count == 0)old_count = 1; for(int col=old_count; col<=new_count; col++){ +#if !(defined(__APPLE__) && (QT_VERSION>=0x040600)) static_column_->setColumnHidden(col, true); static_field_->setColumnHidden(col,true); +#endif this->setItemDelegateForColumn(col, delegate_); } + } } void SequenceTableView::rowCountChanged(const QModelIndex& index, int old_count, int new_count){ if(old_count >= 0 && old_count <= new_count){ +#if !(defined(__APPLE__) && (QT_VERSION>=0x040600)) if(old_count == 0){ old_count = 1; } @@ -286,23 +304,28 @@ void SequenceTableView::rowCountChanged(const QModelIndex& index, int old_count, static_row_->setRowHidden(row, true); static_field_->setRowHidden(row,true); } +#endif } } void SequenceTableView::resizeColumnsToContents(){ QTableView::resizeColumnsToContents(); +#if !(defined(__APPLE__) && (QT_VERSION>=0x040600)) static_column_->setColumnWidth(0,this->columnWidth(0)); static_field_->setColumnWidth(0,this->columnWidth(0)); for(int i = 0; i < this->model()->columnCount(); i++){ static_row_->setColumnWidth(i,this->columnWidth(i)); } + this->updateStaticColumn(); this->updateStaticField(); +#endif } void SequenceTableView::resizeRowsToContents(){ QTableView::resizeRowsToContents(); +#if !(defined(__APPLE__) && (QT_VERSION>=0x040600)) static_row_->setRowHeight(0,this->rowHeight(0)); static_field_->setRowHeight(0,this->rowHeight(0)); for(int i = 0; i < this->model()->columnCount(); i++){ @@ -310,17 +333,21 @@ void SequenceTableView::resizeRowsToContents(){ } this->updateStaticRow(); this->updateStaticField(); +#endif } -QTableView* SequenceTableView::GetStaticRow(){ +QTableView* SequenceTableView::GetStaticRow() +{ return static_row_; } -QTableView* SequenceTableView::GetStaticColumn(){ +QTableView* SequenceTableView::GetStaticColumn() +{ return static_column_; } -QTableView* SequenceTableView::GetStaticField(){ +QTableView* SequenceTableView::GetStaticField() +{ return static_field_; } @@ -352,6 +379,16 @@ void SequenceTableView::wheelEvent(QWheelEvent* event) } } +void SequenceTableView::keyPressEvent(QKeyEvent* event) +{ + if(event->matches(QKeySequence::Copy)){ + emit CopyEvent(event); + } + else{ + QTableView::keyPressEvent(event); + } +} + SequenceTableView::~SequenceTableView(){} }} diff --git a/modules/gui/src/sequence/sequence_table_view.hh b/modules/gui/src/sequence_viewer/sequence_table_view.hh similarity index 95% rename from modules/gui/src/sequence/sequence_table_view.hh rename to modules/gui/src/sequence_viewer/sequence_table_view.hh index f8c07ee813d21cdf6a45fa9e6091bf54705e8502..e138d07eadc8dc63a4c110b4fbcb2900f82bac44 100644 --- a/modules/gui/src/sequence/sequence_table_view.hh +++ b/modules/gui/src/sequence_viewer/sequence_table_view.hh @@ -44,6 +44,7 @@ public: signals: void MouseWheelEvent(QWheelEvent* event); + void CopyEvent(QKeyEvent* event); public slots: void columnCountChanged(const QModelIndex& index, int old_count, int new_count); @@ -55,7 +56,8 @@ protected: virtual void mouseDoubleClickEvent(QMouseEvent* event); virtual void mouseReleaseEvent(QMouseEvent* event); virtual void resizeEvent(QResizeEvent* event); - virtual void wheelEvent (QWheelEvent* event); + virtual void wheelEvent(QWheelEvent* event); + virtual void keyPressEvent(QKeyEvent* event); virtual QModelIndex moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers); void scrollTo (const QModelIndex & index, ScrollHint hint = EnsureVisible); diff --git a/modules/gui/src/sequence_viewer/sequence_view_object.cc b/modules/gui/src/sequence_viewer/sequence_view_object.cc new file mode 100644 index 0000000000000000000000000000000000000000..8b63980bf5fa0a9f1142df964ec8dc5cb8454a7a --- /dev/null +++ b/modules/gui/src/sequence_viewer/sequence_view_object.cc @@ -0,0 +1,213 @@ +//------------------------------------------------------------------------------ +// This file is part of the OpenStructure project <www.openstructure.org> +// +// Copyright (C) 2008-2010 by the OpenStructure authors +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation; either version 3.0 of the License, or (at your option) +// any later version. +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +//------------------------------------------------------------------------------ + +/* + Author: Stefan Scheuber + */ + + +#include <QtGui> + +#include <ost/mol/mol.hh> +#include <ost/mol/view_op.hh> + +#include "sequence_row.hh" +#include "secstr_row.hh" + +#include "sequence_view_object.hh" + +namespace ost { namespace gui { + +const QString SequenceViewObject::properties_mode = "Highlight properties"; +const QString SequenceViewObject::secondary_structure_mode = "Secondary structure"; + +AlignPropertiesPainter* SequenceViewObject::align_properties_painter = new AlignPropertiesPainter(); +ConservationPainter* SequenceViewObject::conservation_painter = new ConservationPainter(); +BackgroundPainter* SequenceViewObject::background_painter = new BackgroundPainter(); +SeqSecStrPainter* SequenceViewObject::seq_secondary_structure_painter = new SeqSecStrPainter(); +SeqSelectionPainter* SequenceViewObject::seq_selection_painter = new SeqSelectionPainter(); +SeqTextPainter* SequenceViewObject::seq_text_painter = new SeqTextPainter(); + +SequenceViewObject::SequenceViewObject(seq::SequenceList& sequences, const QList<QString>& names, QObject *parent): BaseViewObject(parent), entity_(gfx::EntityP()) +{ + this->Init(); + if(names.size() == sequences.GetCount()){ + for(int i=0; i<sequences.GetCount(); i++){ + seq::SequenceHandle seq = sequences[i]; + this->AddSequence(seq, names[i]); + } + } + this->SetDisplayMode(properties_mode); +} + +SequenceViewObject::SequenceViewObject(seq::SequenceHandle& sequence, const QString& name, QObject *parent): BaseViewObject(parent), entity_(gfx::EntityP()) +{ + this->Init(); + this->AddSequence(sequence, name); + this->SetDisplayMode(properties_mode); +} + +SequenceViewObject::SequenceViewObject(mol::ChainView& chain, const QString& name, QObject *parent): BaseViewObject(parent), entity_(gfx::EntityP()) +{ + this->Init(); + this->AddChain(chain, name); + this->SetDisplayMode(properties_mode); +} + +SequenceViewObject::SequenceViewObject(gfx::EntityP& entity, QObject* parent): BaseViewObject(parent), entity_(entity) +{ + this->Init(); + mol::EntityView view =entity->GetView(); + for (mol::ChainViewList::const_iterator c=view.GetChainList().begin(), + e1=view.GetChainList().end(); c!=e1; ++c) { + mol::ChainView chain=*c; + QString name = QString(entity->GetName().c_str()); + if (chain.GetName()!="" && chain.GetName()!=" ") { + name= name + " ("+chain.GetName().c_str()+")"; + } + this->AddChain(chain, name); + } + this->SetDisplayMode(secondary_structure_mode); +} + +SequenceViewObject::SequenceViewObject(QObject* parent): BaseViewObject(parent), entity_(gfx::EntityP()) +{ + this->Init(); + this->SetDisplayMode(properties_mode); +} + +void SequenceViewObject::Init() +{ + this->AddDisplayMode(properties_mode); + if(entity_){ + this->AddDisplayMode(secondary_structure_mode); + } +} + +void SequenceViewObject::AddSequence(seq::SequenceHandle& sequence, const QString& name) +{ + SequenceRow* new_row = new SequenceRow(name, sequence, this); + new_row->InsertPainter(background_painter); + new_row->InsertPainter(align_properties_painter); + new_row->InsertPainter(seq_text_painter); + new_row->InsertPainter(seq_selection_painter); + rows_.append(new_row); +} + +void SequenceViewObject::AddChain(mol::ChainView& chain, const QString& name) +{ + SecStrRow* new_row = new SecStrRow(name, chain, this); + new_row->InsertPainter(background_painter); + new_row->InsertPainter(seq_secondary_structure_painter); + new_row->InsertPainter(seq_text_painter); + new_row->InsertPainter(seq_selection_painter); + rows_.append(new_row); +} + +void SequenceViewObject::AttachGfxObject(gfx::EntityP& ent) +{ + entity_ = ent; +} + +gfx::EntityP& SequenceViewObject::GetGfxObject() +{ + return entity_; +} + +void SequenceViewObject::SetDisplayMode(const QString& mode) +{ + if(this->display_modes_.contains(mode) && mode != this->GetCurrentDisplayMode()){ + if(mode == properties_mode){ + for(int i=0 ; i<this->GetRowCount(); i++){ + BaseRow* row = this->GetRow(i); + row->RemovePainter(seq_secondary_structure_painter); + row->RemovePainter(conservation_painter); + row->InsertPainter(align_properties_painter,1); + } + } + else if(mode == secondary_structure_mode){ + for(int i=0 ; i<this->GetRowCount(); i++){ + BaseRow* row = this->GetRow(i); + row->RemovePainter(align_properties_painter); + row->RemovePainter(conservation_painter); + row->InsertPainter(seq_secondary_structure_painter,1); + } + } + } + BaseViewObject::SetDisplayMode(mode); +} + +QMap<int, QList<int> > SequenceViewObject::GetIndexesForView(const mol::EntityView& view) +{ + if(view.GetChainCount()==0){ + return QMap<int, QList<int> >(); + } + else{ + QMap<int, QList<int> > selected_indexes; + for(int i=0; i< rows_.size(); i++){ + if(SecStrRow* secstr_row = qobject_cast<SecStrRow*>(rows_[i])){ + mol::ChainView dst_chain=(secstr_row->GetChain()); + seq::SequenceHandle seq = secstr_row->GetSequence(); + if (mol::ChainView src_chain=view.FindChain(dst_chain.GetName())) { + // for each residue in the selection deduce index in sequence + for (mol::ResidueViewList::const_iterator j=src_chain.GetResidueList().begin(), + e2=src_chain.GetResidueList().end(); j!=e2; ++j) { + mol::ResidueView dst_res=dst_chain.FindResidue(j->GetHandle()); + assert(dst_res.IsValid()); + int p=dst_res.GetIndex()+1; + assert(p>=0 && p<=seq.GetLength()); + selected_indexes[i].append(p); + } + } + } + } + return selected_indexes; + } +} + +QMap<int, QList<int> > SequenceViewObject::GetIndexesForSubject(const QString& subject, const QString& sequence_name) +{ + if(subject.size()==0){ + return QMap<int, QList<int> >(); + } + QMap<int, QList<int> > selected_indexes; + String subject_str = subject.toStdString(); + for(int i=0; i< rows_.size(); i++){ + if(SequenceRow* secstr_row = qobject_cast<SequenceRow*>(rows_[i])){ + if(sequence_name.size()==0 || sequence_name==secstr_row->GetName()){ + seq::SequenceHandle seq = secstr_row->GetSequence(); + String seq_str=seq.GetString(); + size_t pos=0; + size_t first=String::npos; + while ((pos=seq_str.find(subject_str, pos))!=String::npos) { + if (first==String::npos) { + first=pos; + } + for(int j=0; j < subject.size(); j++){ + selected_indexes[i].append(pos+j+1); + } + pos+=subject.length(); + } + } + } + } + return selected_indexes; +} + +}} diff --git a/modules/gui/src/sequence/view_object.hh b/modules/gui/src/sequence_viewer/sequence_view_object.hh similarity index 54% rename from modules/gui/src/sequence/view_object.hh rename to modules/gui/src/sequence_viewer/sequence_view_object.hh index a6d99bc74c2a84d3c91f2d273c9855136e1ce502..2ad390a95bd9a19a91ae3db86c05ac90a297e2ec 100644 --- a/modules/gui/src/sequence/view_object.hh +++ b/modules/gui/src/sequence_viewer/sequence_view_object.hh @@ -16,50 +16,44 @@ // along with this library; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA //------------------------------------------------------------------------------ -#ifndef OST_SEQUENCE_VIEWER_VIEW_OBJECT -#define OST_SEQUENCE_VIEWER_VIEW_OBJECT +#ifndef OST_SEQUENCE_VIEWER_SEQUENCE_VIEW_OBJECT +#define OST_SEQUENCE_VIEWER_SEQUENCE_VIEW_OBJECT /* Author: Stefan Scheuber */ -#include <QObject> -#include <QPair> -#include <QList> -#include <QVarLengthArray> -#include <QFont> -#include <QSize> -#include <ost/mol/alg/sec_structure_segments.hh> #include <ost/mol/entity_handle.hh> #include <ost/gfx/entity.hh> #include <ost/seq/sequence_list.hh> -#include "base_row.hh" +#include "align_properties_painter.hh" +#include "conservation_painter.hh" +#include "background_painter.hh" +#include "seq_secstr_painter.hh" +#include "seq_selection_painter.hh" +#include "seq_text_painter.hh" + +#include "base_view_object.hh" namespace ost { namespace gui { -class ViewObject : public QObject +class SequenceViewObject : public BaseViewObject { Q_OBJECT - public: - ViewObject(seq::SequenceList& sequences, const QList<QString>& names, QObject* parent = 0); - ViewObject(seq::SequenceHandle& sequence, const QString& name, QObject* parent = 0); - ViewObject(mol::ChainView& chain, const QString& name, QObject* parent = 0); - ViewObject(gfx::EntityP& entity, QObject* parent = 0); - ViewObject(QObject* parent = 0); + SequenceViewObject(seq::SequenceList& sequences, const QList<QString>& names, QObject* parent = 0); + SequenceViewObject(seq::SequenceHandle& sequence, const QString& name, QObject* parent = 0); + SequenceViewObject(mol::ChainView& chain, const QString& name, QObject* parent = 0); + SequenceViewObject(gfx::EntityP& entity, QObject* parent = 0); + SequenceViewObject(QObject* parent = 0); - void InsertRow(int pos, BaseRow* row); - void RemoveRow(BaseRow* row); - - BaseRow* GetRow(int pos); - int GetRowCount(); - int GetMaxColumnCount() const; + void Init(); void AddSequence(seq::SequenceHandle& sequence, const QString& name=QString()); void AddChain(mol::ChainView& chain, const QString& name=QString()); @@ -67,21 +61,26 @@ public: void AttachGfxObject(gfx::EntityP& ent); gfx::EntityP& GetGfxObject(); - void SetSelection(int row, const QSet<int>& added, const QSet<int>& removed); + virtual void SetDisplayMode(const QString& mode); - QVariant GetData(int row, int column, int role); - bool SetData(int row, int column, const QVariant& value, int role); - Qt::ItemFlags Flags(int row, int column) const; + QMap<int, QList<int> > GetIndexesForView(const mol::EntityView& view); + QMap<int, QList<int> > GetIndexesForSubject(const QString& subject, const QString& sequence_name=QString()); - void DoubleClicked(int row, int column); - void ZoomIn(); - void ZoomOut(); +protected: + static const QString properties_mode; + static const QString secondary_structure_mode; - QMap<int, QList<int> > GetIndexesForView(const mol::EntityView& view); + static AlignPropertiesPainter* align_properties_painter; + static ConservationPainter* conservation_painter; + static BackgroundPainter* background_painter; + static SeqSecStrPainter* seq_secondary_structure_painter; + static SeqSelectionPainter* seq_selection_painter; + static SeqTextPainter* seq_text_painter; private: - QList<BaseRow*> rows_; gfx::EntityP entity_; + + }; diff --git a/modules/gui/src/sequence_viewer/sequence_viewer.cc b/modules/gui/src/sequence_viewer/sequence_viewer.cc index 05d5d03cf1c64f68a374105eee97fe1bafb3b979..c5d86d7834cb9557d387faefb0f96d02c243eec3 100644 --- a/modules/gui/src/sequence_viewer/sequence_viewer.cc +++ b/modules/gui/src/sequence_viewer/sequence_viewer.cc @@ -16,25 +16,54 @@ // along with this library; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA //------------------------------------------------------------------------------ + +/* + Author: Stefan Scheuber + */ +#include <boost/pointer_cast.hpp> + +#include <QAbstractItemView> +#include <QApplication> +#include <QClipboard> +#include <QDir> +#include <QHeaderView> #include <QMenu> +#include <QPushButton> +#include <QShortcut> +#include <QVBoxLayout> +#include <QVarLengthArray> -#include <ost/dyn_cast.hh> -#include <ost/mol/view_op.hh> +#include <ost/platform.hh> +#include <ost/mol/chain_view.hh> +#include <ost/mol/entity_view.hh> + +#include <ost/seq/sequence_handle.hh> #include <ost/gfx/entity.hh> #include <ost/gfx/scene.hh> #include <ost/gfx/gfx_node_visitor.hh> -#include <ost/gfx/gfx_node.hh> -#include <ost/gfx/gfx_object.hh> #include <ost/gui/widget_registry.hh> #include <ost/gui/gosty_app.hh> +#include "sequence_model.hh" #include "sequence_viewer.hh" - namespace ost { namespace gui { +class SequenceViewerFactory: public WidgetFactory { +public: + SequenceViewerFactory() : + WidgetFactory("ost::gui::SequenceViewer", "Sequence Viewer") { + } + + virtual Widget* Create(QWidget* parent) { + return GostyApp::Instance()->GetSequenceViewer(); + } +}; + +OST_REGISTER_WIDGET(SequenceViewer, SequenceViewerFactory); + struct GetNodesVisitor: public gfx::GfxNodeVisitor { GetNodesVisitor(): nodes_() {} virtual void VisitObject(gfx::GfxObj* o, const Stack& st) { @@ -44,199 +73,349 @@ struct GetNodesVisitor: public gfx::GfxNodeVisitor { gfx::NodePtrList GetNodes(){return nodes_;} }; -class SequenceViewerFactory: public WidgetFactory { -public: - SequenceViewerFactory() : - WidgetFactory("ost::gui::SequenceViewer", "Sequence Viewer") { +SequenceViewer::SequenceViewer(bool stand_alone, QWidget* parent): Widget(NULL,parent) +{ + model_ = new SequenceModel(this); + + QVBoxLayout* layout = new QVBoxLayout(this); + layout->setMargin(0); + layout->setSpacing(0); + this->setLayout(layout); + + this->InitActions(); + + + if(stand_alone){ + this->InitMenuBar(); } + this->InitSearchBar(); + this->InitView(); - virtual Widget* Create(QWidget* parent) { - return GostyApp::Instance()->GetSequenceViewer(); + if(!stand_alone){ + gfx::Scene::Instance().AttachObserver(this); + gfx::GfxNodeP root_node = gfx::Scene::Instance().GetRootNode(); + GetNodesVisitor gnv; + gfx::Scene::Instance().Apply(gnv); + gfx::NodePtrList list = gnv.GetNodes(); + for(unsigned int i=0; i<list.size();i++){ + this->NodeAdded(list[i]); + } } -}; +} -OST_REGISTER_WIDGET(SequenceViewer, SequenceViewerFactory); +void SequenceViewer::InitMenuBar() +{ + toolbar_ = new QToolBar(this); + toolbar_->setToolButtonStyle(Qt::ToolButtonIconOnly); + toolbar_->setIconSize(QSize(16,16)); + toolbar_->addActions(action_list_); + layout()->addWidget(toolbar_); +} -SequenceViewer::SequenceViewer(QWidget* parent): - SequenceViewerBase(parent), we_are_changing_the_selection_(false) +void SequenceViewer::InitSearchBar() { - gfx::Scene::Instance().AttachObserver(this); - this->SetDisplayStyle(SequenceViewer::LOOSE); + seq_search_bar_ = new SeqSearchBar(this); + seq_search_bar_->hide(); + layout()->addWidget(seq_search_bar_); + connect(seq_search_bar_, SIGNAL(Changed(const QString&, bool, const QString&)), this, SLOT(OnSearchBarUpdate(const QString&, bool, const QString&))); +} - gfx::GfxNodeP root_node = gfx::Scene::Instance().GetRootNode(); - GetNodesVisitor gnv; - gfx::Scene::Instance().Apply(gnv); - gfx::NodePtrList list = gnv.GetNodes(); - for(unsigned int i=0; i<list.size();i++){ - this->NodeAdded(list[i]); - } +void SequenceViewer::InitView() +{ + seq_table_view_ = new SequenceTableView(model_); + layout()->addWidget(seq_table_view_); + + connect(model_,SIGNAL(columnsInserted(const QModelIndex&, int, int)),seq_table_view_,SLOT(columnCountChanged(const QModelIndex&, int, int))); + connect(model_,SIGNAL(rowsInserted(const QModelIndex&, int, int)),seq_table_view_,SLOT(rowCountChanged(const QModelIndex&, int, int))); + + seq_table_view_->horizontalHeader()->setMinimumSectionSize(2); + seq_table_view_->verticalHeader()->setMinimumSectionSize(2); + seq_table_view_->setSelectionMode(QAbstractItemView::ExtendedSelection); + connect(seq_table_view_->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), this, SLOT(SelectionModelChanged(const QItemSelection&, const QItemSelection&))); + connect(seq_table_view_,SIGNAL(doubleClicked(const QModelIndex&)),model_,SLOT(DoubleClicked(const QModelIndex&))); +#if !(defined(__APPLE__) && (QT_VERSION>=0x040600)) + connect(seq_table_view_->GetStaticColumn(),SIGNAL(doubleClicked(const QModelIndex&)),this,SLOT(DoubleClicked(const QModelIndex&))); + connect(seq_table_view_->GetStaticRow(),SIGNAL(doubleClicked(const QModelIndex&)),this,SLOT(DoubleClicked(const QModelIndex&))); +#endif + connect(seq_table_view_,SIGNAL(CopyEvent(QKeyEvent*)),this,SLOT(CopyEvent(QKeyEvent*))); + connect(seq_table_view_,SIGNAL(MouseWheelEvent(QWheelEvent*)),this,SLOT(MouseWheelEvent(QWheelEvent*))); } -SequenceViewer::~SequenceViewer() +void SequenceViewer::InitActions() { - gfx::Scene::Instance().DetachObserver(this); + QDir icon_path(GetSharedDataPath().c_str()); + icon_path.cd("gui"); + icon_path.cd("icons"); + + QAction* find_action = new QAction(this); + find_action->setText("Find Dialog"); + find_action->setShortcut(QKeySequence(tr("Ctrl+F"))); + find_action->setCheckable(true); + find_action->setToolTip("Display Find-Dialog (Ctrl+F)"); + find_action->setIcon(QIcon(icon_path.absolutePath()+QDir::separator()+QString("find_icon.png"))); + action_list_.append(find_action); + connect(find_action, SIGNAL(triggered(bool)), this, SLOT(FindInSequence())); + + display_mode_actions_ = new QActionGroup(this); + QAction* menu_action = new QAction(this); + menu_action->setText("Menubar"); + menu_action->setShortcut(QKeySequence(tr("Ctrl+M"))); + menu_action->setToolTip("Display Options (Ctrl+M)"); + menu_action->setIcon(QIcon(icon_path.absolutePath()+QDir::separator()+QString("menubar_icon.png"))); + action_list_.append(menu_action); + connect(menu_action, SIGNAL(triggered(bool)), this, SLOT(DisplayMenu())); } void SequenceViewer::NodeAdded(const gfx::GfxNodeP& n) { - if (gfx::EntityP o=dyn_cast<gfx::Entity>(n)) { - // extract all chains - mol::EntityView v=o->GetView(); - for (mol::ChainViewList::const_iterator c=v.GetChainList().begin(), - e1=v.GetChainList().end(); c!=e1; ++c) { - mol::ChainView chain=*c; - String seq_str; - seq_str.reserve(chain.GetResidueCount()); - for (mol::ResidueViewList::const_iterator r=chain.GetResidueList().begin(), - e2=chain.GetResidueList().end(); r!=e2; ++r) { - mol::ResidueView res=*r; - seq_str.append(1, res.GetOneLetterCode()); - } - if (seq_str.empty()) { - continue; - } - String name=o->GetName(); - if (chain.GetName()!="" && chain.GetName()!=" ") { - name+=" ("+chain.GetName()+")"; - } - seq::SequenceHandle seq=seq::CreateSequence(name, seq_str); - mol::EntityView v_one_chain=v.GetHandle().CreateEmptyView(); - v_one_chain.AddChain(chain, mol::ViewAddFlag::INCLUDE_ALL); - seq.AttachView(v_one_chain); - SequenceItem* item=new SequenceItem(seq); - connect(item, SIGNAL(SelectionChanged(SequenceItem*)), - this, SLOT(ItemSelectionChanged(SequenceItem*))); - this->AddSequence(item); - obj_map_.insert(std::make_pair(item, o)); - } + if (gfx::EntityP o=boost::dynamic_pointer_cast<gfx::Entity>(n)) { + model_->InsertGfxEntity(o); + seq_table_view_->resizeColumnsToContents(); + seq_table_view_->resizeRowsToContents(); + } + this->UpdateSearchBar(); +} + +void SequenceViewer::NodeRemoved(const gfx::GfxNodeP& node) +{ + if (gfx::EntityP o=boost::dynamic_pointer_cast<gfx::Entity>(node)) { + model_->RemoveGfxEntity(o); + } +} + +void SequenceViewer::AddAlignment(const seq::AlignmentHandle& alignment) +{ + if(alignment.GetCount()>0 && alignment.GetLength()>0){ + model_->InsertAlignment(alignment); + seq_table_view_->resizeColumnsToContents(); + seq_table_view_->resizeRowsToContents(); } } -void SequenceViewer::ItemSelectionChanged(SequenceItem* item) +void SequenceViewer::RemoveAlignment(const seq::AlignmentHandle& alignment) +{ + model_->RemoveAlignment(alignment); +} + +void SequenceViewer::UpdateSearchBar() +{ + QStringList sequence_names_; + for(int i = 1; i< model_->rowCount(); i++){ + QString name = model_->data(model_->index(i,0),Qt::DisplayRole).toString(); + sequence_names_.append(name); + } + seq_search_bar_->UpdateItems(sequence_names_); +} + +void SequenceViewer::SelectionModelChanged(const QItemSelection& sel, const QItemSelection& desel) +{ + gfx::Scene::Instance().DetachObserver(this); + model_->SelectionChanged(sel, desel); + gfx::Scene::Instance().AttachObserver(this); +} + +void SequenceViewer::SelectionChanged(const gfx::GfxObjP& o, + const mol::EntityView& view) { - if (we_are_changing_the_selection_==true) { - return; + disconnect(seq_table_view_->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), this, SLOT(SelectionModelChanged(const QItemSelection&, const QItemSelection&))); + gfx::EntityP entity=boost::dynamic_pointer_cast<gfx::Entity>(o); + if(entity){ + const QModelIndexList& list = model_->GetModelIndexes(entity, view); + this->SelectList(list); } - we_are_changing_the_selection_=true; - // map sequence item back to graphical object - if (gfx::GfxObjP p=this->GfxObjForSeqItem(item)) { - gfx::EntityP ec=dyn_cast<gfx::Entity>(p); - seq::SequenceHandle seq=item->GetSequence(); - mol::EntityView att_v=seq.GetAttachedView(); - if (!att_v) { - we_are_changing_the_selection_=false; - return; + connect(seq_table_view_->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), this, SLOT(SelectionModelChanged(const QItemSelection&, const QItemSelection&))); +} + +void SequenceViewer::DoubleClicked(const QModelIndex& index) +{ + disconnect(seq_table_view_->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), this, SLOT(SelectionModelChanged(const QItemSelection&, const QItemSelection&))); + model_->DoubleClicked(index); + connect(seq_table_view_->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), this, SLOT(SelectionModelChanged(const QItemSelection&, const QItemSelection&))); +} + +void SequenceViewer::MouseWheelEvent(QWheelEvent* event) +{ + int delta = event->delta(); + if (event->orientation() == Qt::Vertical) { + if(delta>0){ + model_->ZoomIn(); + seq_table_view_->viewport()->update(); + seq_table_view_->resizeColumnsToContents(); + seq_table_view_->resizeRowsToContents(); } - const SequenceItem::Selection& sel=item->GetSelection(); - // reset selection of "our" chain - mol::EntityView sel_v=ec->GetSelection(); - if (mol::ChainView c=sel_v.FindChain(att_v.GetChainList().front().GetHandle())) { - sel_v.RemoveChain(c); + else if(delta<0){ + model_->ZoomOut(); + seq_table_view_->viewport()->update(); + seq_table_view_->resizeColumnsToContents(); + seq_table_view_->resizeRowsToContents(); } - if (sel.empty()) { - try { - ec->SetSelection(sel_v); - } catch(...) { + } + event->accept(); +} + +void SequenceViewer::CopyEvent(QKeyEvent* event) +{ + QItemSelectionModel* model = seq_table_view_->selectionModel(); + const QModelIndexList& list = model->selectedIndexes(); + if(list.size()>0){ + QString clipboard_string; + QSet<int> rows; + int min_col=model_->columnCount(); + int max_col=0; + for(int i = 0; i < list.size(); i++){ + if(list[i].column()>max_col){ + max_col = list[i].column(); + } + if(list[i].column()<min_col){ + min_col = list[i].column(); } - we_are_changing_the_selection_=false; - return; - } - for (SequenceItem::Selection::const_iterator j=sel.begin(), - e=sel.end(); j!=e; ++j) { - for (size_t k=j->Loc; k<j->End(); ++k) { - if (int(k)>seq.GetLength() || seq.GetOneLetterCode(k)=='-') { - continue; + rows.insert(list[i].row()); + } + + bool first_row = true; + for(int i = 1; i < model_->rowCount(); i++){ + if(rows.contains(i)){ + if(!first_row){ + clipboard_string.append("\n"); } - if (mol::ResidueView rv=seq.GetResidue(k)) { - sel_v.AddResidue(rv, mol::ViewAddFlag::INCLUDE_ATOMS); + for(int j=min_col; j<=max_col; j++){ + const QModelIndex& index = model_->index(i,j); + if(model->isSelected(index)){ + clipboard_string.append(model_->data(index,Qt::DisplayRole).toString()); + } + else{ + clipboard_string.append('-'); + } } + first_row = false; } } - sel_v.AddAllInclusiveBonds(); - try { - ec->SetSelection(sel_v); - } catch(...) { - } + QApplication::clipboard()->setText(clipboard_string); + } + event->accept(); +} +void SequenceViewer::FindInSequence() +{ + if(seq_search_bar_->isHidden()){ + seq_search_bar_->show(); + } + else{ + seq_search_bar_->hide(); } - we_are_changing_the_selection_=false; } -void SequenceViewer::NodeRemoved(const gfx::GfxNodeP& node) +void SequenceViewer::OnSearchBarUpdate(const QString& subject, + bool search_in_all, const QString& name) { - if (gfx::EntityP o=dyn_cast<gfx::Entity>(node)) { - SequenceItemList seq_items=this->SeqItemsForGfxObj(o); - for (SequenceItemList::iterator i=seq_items.begin(), - e=seq_items.end(); i!=e; ++i) { - SequenceItem* seq_item=*i; - this->RemoveSequence(seq_item); - delete seq_item; - } + seq_table_view_->selectionModel()->clear(); + if(search_in_all){ + const QModelIndexList& list = model_->GetModelIndexes(subject); + this->SelectList(list); + } + else{ + const QModelIndexList& list = model_->GetModelIndexes(subject,name); + this->SelectList(list); } } -void SequenceViewer::SelectionChanged(const gfx::GfxObjP& o, - const mol::EntityView& view) +void SequenceViewer::SelectList(const QModelIndexList& list) { - if (we_are_changing_the_selection_) { - return; + QItemSelectionModel* model = seq_table_view_->selectionModel(); + QSet<int> rows_visited; + for(int i = 0; i<list.size(); i++){ + int row =list[i].row(); + if(!rows_visited.contains(row)){ + model->select(list[i],QItemSelectionModel::Rows|QItemSelectionModel::Deselect); + rows_visited.insert(row); + } } - we_are_changing_the_selection_=true; - gfx::EntityP ec=dyn_cast<gfx::Entity>(o); - + for(int i = 0; i<list.size(); i++){ + model->select(list[i],QItemSelectionModel::Select); + } +} - std::vector<bool> selected_cols; - selected_cols.resize(this->GetLongestSequenceLength(), false); +const QStringList& SequenceViewer::GetDisplayModes() +{ + return model_->GetDisplayModes(); +} +const QStringList& SequenceViewer::GetDisplayModes(const seq::AlignmentHandle& alignment) +{ + return model_->GetDisplayModes(alignment); +} +const QStringList& SequenceViewer::GetDisplayModes(const gfx::EntityP& entity) +{ + return model_->GetDisplayModes(entity); +} - // get affected sequence items - SequenceItemList seq_items=this->SeqItemsForGfxObj(o); +const QString& SequenceViewer::GetCurrentDisplayMode() +{ + return model_->GetCurrentDisplayMode(); +} +const QString& SequenceViewer::GetCurrentDisplayMode(const seq::AlignmentHandle& alignment) +{ + return model_->GetCurrentDisplayMode(alignment); +} +const QString& SequenceViewer::GetCurrentDisplayMode(const gfx::EntityP& entity) +{ + return model_->GetCurrentDisplayMode(entity); +} - for (SequenceItemList::iterator i=seq_items.begin(), - e=seq_items.end(); i!=e; ++i) { - SequenceItem* seq_item=*i; +void SequenceViewer::ChangeDisplayMode(const QString& string) +{ + model_->SetDisplayMode(string); + seq_table_view_->viewport()->update(); +} - if(view.GetChainCount()==0){ - this->SelectColumns(seq_item, selected_cols); - } - else - { - seq::SequenceHandle seq=seq_item->GetSequence(); - mol::ChainView dst_chain=(seq.GetAttachedView().GetChainList())[0]; - if (mol::ChainView src_chain=view.FindChain(dst_chain.GetName())) { - // for each residue in the selection deduce index in sequence - for (mol::ResidueViewList::const_iterator j=src_chain.GetResidueList().begin(), - e2=src_chain.GetResidueList().end(); j!=e2; ++j) { - mol::ResidueView dst_res=dst_chain.FindResidue(j->GetHandle()); - assert(dst_res.IsValid()); - int p=seq.GetPos(dst_res.GetIndex()); - assert(p>=0 && p<=seq.GetLength()); - selected_cols[p]=true; - } - this->SelectColumns(seq_item, selected_cols); - std::fill(selected_cols.begin(), selected_cols.end(), false); - } - } - } - we_are_changing_the_selection_=false; +void SequenceViewer::ChangeDisplayMode(const seq::AlignmentHandle& alignment, const QString& string) +{ + model_->SetDisplayMode(alignment, string); + seq_table_view_->viewport()->update(); } -SequenceItemList SequenceViewer::SeqItemsForGfxObj(const gfx::GfxObjP& obj) +void SequenceViewer::ChangeDisplayMode(const gfx::EntityP& entity, const QString& string) { - SequenceItemList seq_items; - gfx::EntityP ec=dyn_cast<gfx::Entity>(obj); - std::map<SequenceItem*, gfx::EntityP>::iterator i,e; - for (i=obj_map_.begin(), e=obj_map_.end(); i!=e; ++i) { - if (i->second==ec) { - seq_items.push_back(i->first); + model_->SetDisplayMode(entity, string); + seq_table_view_->viewport()->update(); +} + +ActionList SequenceViewer::GetActions() +{ + return action_list_; +} + +void SequenceViewer::DisplayMenu() +{ + QMenu* menu = new QMenu(); + QList<QAction*> actions = display_mode_actions_->actions(); + for(int i=0;i<actions.size();i++){ + display_mode_actions_->removeAction(actions[i]); + } + const QStringList& display_modes = this->GetDisplayModes(); + for(int i=0; i<display_modes.size(); i++){ + QString ident(display_modes[i]); + QAction* action = new QAction(ident,menu); + action->setCheckable(true); + connect(action,SIGNAL(triggered(bool)),this,SLOT(ChangeDisplayMode())); + display_mode_actions_->addAction(action); + if(display_modes[i] == this->GetCurrentDisplayMode() ){ + action->setChecked(true); } + menu->addAction(action); } - return seq_items; + menu->exec(QCursor::pos()); } -gfx::GfxObjP SequenceViewer::GfxObjForSeqItem(SequenceItem* item) +void SequenceViewer::ChangeDisplayMode() { - std::map<SequenceItem*, gfx::EntityP>::iterator i=obj_map_.find(item); - return (i!=obj_map_.end()) ? i->second : gfx::EntityP(); + QAction* action = display_mode_actions_->checkedAction(); + if(action){ + this->ChangeDisplayMode(action->text()); + } +} + +SequenceViewer::~SequenceViewer(){ + gfx::Scene::Instance().DetachObserver(this); } }} diff --git a/modules/gui/src/sequence_viewer/sequence_viewer.hh b/modules/gui/src/sequence_viewer/sequence_viewer.hh index 0b5811dc1fb17fd7905501845b01a77d592d75c8..e4f8d55f2638b6abfc260e4eec4bf6a43c629a54 100644 --- a/modules/gui/src/sequence_viewer/sequence_viewer.hh +++ b/modules/gui/src/sequence_viewer/sequence_viewer.hh @@ -16,45 +16,93 @@ // along with this library; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA //------------------------------------------------------------------------------ -#ifndef OST_SEQUENCE_VIEWER_HH -#define OST_SEQUENCE_VIEWER_HH +#ifndef OST_SEQUENCE_VIEWER_SEQUENCE_VIEWER +#define OST_SEQUENCE_VIEWER_SEQUENCE_VIEWER /* - Author: Marco Biasini + Author: Stefan Scheuber */ -#include <map> +#include <QWidget> +#include <QActionGroup> +#include <QToolBar> -#include <ost/gfx/scene_observer.hh> -#include <ost/gui/sequence_viewer/sequence_viewer_base.hh> -#include <ost/gfx/entity.hh> +#include <ost/seq/alignment_handle.hh> -namespace ost { namespace gui { +#include <ost/gfx/scene.hh> +#include <ost/gfx/gfx_object.hh> + +#include <ost/gui/widget.hh> + +#include <ost/gui/module_config.hh> -class SequenceItem; +#include "sequence_search_bar.hh" +#include "sequence_model.hh" +#include "sequence_table_view.hh" + +namespace ost { namespace gui { -/// \brief sequence view -class DLLEXPORT_OST_GUI SequenceViewer : public SequenceViewerBase, - public gfx::SceneObserver { +/// \brief QTableView with first column not moving +class DLLEXPORT_OST_GUI SequenceViewer : public Widget, public gfx::SceneObserver { Q_OBJECT public: - SequenceViewer(QWidget* parent=NULL); + SequenceViewer(bool stand_alone=true, QWidget* parent=NULL); ~SequenceViewer(); - + virtual void NodeAdded(const gfx::GfxNodeP& node); - virtual void NodeRemoved(const gfx::GfxNodeP& node); - - virtual void SelectionChanged(const gfx::GfxObjP& obj, const mol::EntityView& sel); + virtual void SelectionChanged(const gfx::GfxObjP& o, const mol::EntityView& view); + + virtual void AddAlignment(const seq::AlignmentHandle& alignment); + virtual void RemoveAlignment(const seq::AlignmentHandle& alignment); + + virtual bool Restore(const QString&){return true;}; + virtual bool Save(const QString&){return true;}; + + virtual const QStringList& GetDisplayModes(); + virtual const QStringList& GetDisplayModes(const seq::AlignmentHandle& alignment); + virtual const QStringList& GetDisplayModes(const gfx::EntityP& entity); + + virtual const QString& GetCurrentDisplayMode(); + virtual const QString& GetCurrentDisplayMode(const seq::AlignmentHandle& alignment); + virtual const QString& GetCurrentDisplayMode(const gfx::EntityP& entity); + + virtual ActionList GetActions(); + public slots: - void ItemSelectionChanged(SequenceItem* item); + void ChangeDisplayMode(const QString&); + void ChangeDisplayMode(const seq::AlignmentHandle&, const QString&); + void ChangeDisplayMode(const gfx::EntityP&, const QString&); + void DisplayMenu(); + //internal + void OnSearchBarUpdate(const QString&, bool, const QString&); + private: - SequenceItemList SeqItemsForGfxObj(const gfx::GfxObjP& obj); - gfx::GfxObjP GfxObjForSeqItem(SequenceItem* seq_item); - std::map<SequenceItem*, gfx::EntityP> obj_map_; - bool we_are_changing_the_selection_; + void InitActions(); + void InitView(); + void InitSearchBar(); + void InitMenuBar(); + void UpdateSearchBar(); + void SelectList(const QModelIndexList& list); + QToolBar* toolbar_; + SeqSearchBar* seq_search_bar_; + SequenceModel* model_; + SequenceTableView* seq_table_view_; + + ActionList action_list_; + + QActionGroup* display_mode_actions_; + +private slots: + void ChangeDisplayMode(); + void FindInSequence(); + void SelectionModelChanged(const QItemSelection&, const QItemSelection&); + void DoubleClicked(const QModelIndex& index); + void MouseWheelEvent(QWheelEvent* event); + void CopyEvent(QKeyEvent* event); + }; - + }} #endif diff --git a/modules/gui/src/sequence_viewer/sequence_viewer_base.cc b/modules/gui/src/sequence_viewer/sequence_viewer_base.cc deleted file mode 100644 index 61cae9aac9015f3c3db6a27741a12c7f84da109a..0000000000000000000000000000000000000000 --- a/modules/gui/src/sequence_viewer/sequence_viewer_base.cc +++ /dev/null @@ -1,237 +0,0 @@ -//------------------------------------------------------------------------------ -// This file is part of the OpenStructure project <www.openstructure.org> -// -// Copyright (C) 2008-2010 by the OpenStructure authors -// -// This library is free software; you can redistribute it and/or modify it under -// the terms of the GNU Lesser General Public License as published by the Free -// Software Foundation; either version 3.0 of the License, or (at your option) -// any later version. -// This library is distributed in the hope that it will be useful, but WITHOUT -// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -// details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this library; if not, write to the Free Software Foundation, Inc., -// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -//------------------------------------------------------------------------------ -#include "sequence_viewer_base.hh" -#include "sequence_search_bar.hh" -#include <QShortcut> -#include <QVBoxLayout> -#include <QPainter> - -namespace ost { namespace gui { - -SequenceViewerBase::SequenceViewerBase(QWidget* parent): - Widget(NULL, parent), style_(DENSE), sel_mode_(ROW), - scene_(new SequenceScene(this)), search_bar_(new SequenceSearchBar(this)), - view_(new QGraphicsView(NULL, this)) -{ - QVBoxLayout* l=new QVBoxLayout; - this->setLayout(l); - l->setMargin(0); - l->setSpacing(0); - view_->setScene(scene_); - l->addWidget(search_bar_, 0); - l->addWidget(view_, 1); - view_->setScene(scene_); - view_->setRenderHints(QPainter::Antialiasing|QPainter::TextAntialiasing); - view_->setViewportUpdateMode(QGraphicsView::FullViewportUpdate); - QShortcut* shortcut=new QShortcut(QKeySequence(tr("Ctrl+F")), this); - connect(shortcut, SIGNAL(activated()), this, SLOT(FindInSequence())); - connect(search_bar_, SIGNAL(Changed(const QString&, bool, int)), this, - SLOT(OnSearchBarUpdate(const QString&, bool, int))); - search_bar_->hide(); - view_->setAlignment(Qt::AlignLeft|Qt::AlignTop); -} - -namespace { - -size_t update_select_state(seq::SequenceHandle seq, const String& subject, - std::vector<bool>& sel_state) -{ - size_t pos=0; - size_t first=String::npos; - String seq_str=seq.GetString(); - while ((pos=seq_str.find(subject, pos))!=String::npos) { - if (first==String::npos) { - first=pos; - } - std::fill_n(sel_state.begin()+pos, subject.length(), true); - pos+=subject.length(); - } - return first; -} - - -void set_sel(std::vector<bool>& selected, SequenceItem* item) -{ - std::vector<bool>::iterator c=selected.begin(); - item->ClearSelection(); - while (c!=selected.end()) { - std::vector<bool>::iterator e=c; - while ((*(++e))==*c && e!=selected.end()) {} - if (*c) { - // this is really ugly! - item->BeginSelectionChange(); - item->Select(c-selected.begin(), e-selected.begin(), false); - } - c=e; - } - item->EndSelectionChange(); -} - -} - -void SequenceViewerBase::FindInSequence() -{ - if (scene_->GetSequences().empty()) { - return; - } - search_bar_->Show(scene_->GetSequences()); -} - -int SequenceViewerBase::GetLongestSequenceLength() const -{ - std::vector<SequenceItem*>::iterator i=scene_->GetSequences().begin(), - e=scene_->GetSequences().end(); - int longest=0; - for (; i!=e; ++i) { - longest=std::max(longest, (*i)->GetSequence().GetLength()); - } - return longest; -} - -void SequenceViewerBase::SelectColumns(std::vector<bool>& selected_cols) -{ - std::vector<SequenceItem*>::iterator i=scene_->GetSequences().begin(), - e=scene_->GetSequences().end(); - for (; i!=e; ++i) { - set_sel(selected_cols, *i); - } -} - -void SequenceViewerBase::SelectColumns(SequenceItem* seq_item, - std::vector<bool>& selected_cols) -{ - set_sel(selected_cols, seq_item); -} - -void SequenceViewerBase::ClearSelection() -{ - std::vector<SequenceItem*>::iterator i=scene_->GetSequences().begin(), - e=scene_->GetSequences().end(); - for (; i!=e; ++i) { - (*i)->ClearSelection(); - } -} - -void SequenceViewerBase::OnSearchBarUpdate(const QString& subject, - bool search_in_all, int seq_id) -{ - String std_subj=subject.toStdString(); - this->ClearSelection(); - if (scene_->GetSequences().empty() || (seq_id==-1 && !search_in_all)) { - return; - } - if (subject.size()==0) { - return; - } - - std::vector<bool> selected; - selected.resize(GetLongestSequenceLength(), false); - /// \todo implement selection for SelMode==COLUMN - std::pair<int, size_t> first(0, String::npos); - if (search_in_all) { - for (size_t i=0; i<scene_->GetSequences().size(); ++i) { - (scene_->GetSequences())[i]->ClearSelection(); - seq::SequenceHandle s=(scene_->GetSequences())[i]->GetSequence(); - size_t pos=update_select_state(s, std_subj, selected); - if (pos!=String::npos && first.second==String::npos) { - first.second=pos; - first.first=i; - } - if (sel_mode_==ROW) { - set_sel(selected, (scene_->GetSequences())[i]); - std::fill_n(selected.begin(), selected.size(), false); - } - } - } else { - first.first=seq_id; - SequenceItem* s=(scene_->GetSequences())[seq_id]; - size_t pos=update_select_state(s->GetSequence(), std_subj, selected); - if (pos!=String::npos) { - first.second=pos; - } - if (sel_mode_==ROW) { - set_sel(selected, s); - } - } - if (sel_mode_==COLUMN) { - this->SelectColumns(selected); - } - if (first.second!=String::npos) { - QRectF r=(scene_->GetSequences()[first.first]->GetCharBounds(first.second)); - - view_->ensureVisible(r); - } - scene_->update(); -} - -void SequenceViewerBase::SetDisplayStyle(Style style) -{ - style_=style; - for (std::vector<SequenceItem*>::iterator i=scene_->GetSequences().begin(), - e=scene_->GetSequences().end(); i!=e; ++i) { - (*i)->SetShowSecStructure(style_==LOOSE); - } - scene_->RepackSequences(); -} - -void SequenceViewerBase::SetSelMode(SelMode mode) -{ - sel_mode_=mode; -} - -SequenceViewerBase::SelMode SequenceViewerBase::GetSelMode() const -{ - return sel_mode_; -} - -SequenceViewerBase::Style SequenceViewerBase::GetDisplayStyle() const -{ - return style_; -} - -void SequenceViewerBase::AddSequence(SequenceItem* seq) -{ - seq->SetShowSecStructure(style_==LOOSE); - scene_->AddSequence(seq); - QRectF rect=scene_->itemsBoundingRect(); - view_->setSceneRect(QRectF(0, 0, +rect.left()+rect.width(), - rect.height()+rect.top())); -} - -void SequenceViewerBase::RemoveSequence(SequenceItem* seq) -{ - scene_->RemoveSequence(seq); -} - -void SequenceViewerBase::Clear() -{ - -} - -bool SequenceViewerBase::Restore(const QString& prefix) -{ - return true; -} - -bool SequenceViewerBase::Save(const QString& prefix) -{ - return true; -} - -}} diff --git a/modules/gui/src/sequence_viewer/sequence_viewer_base.hh b/modules/gui/src/sequence_viewer/sequence_viewer_base.hh deleted file mode 100644 index 6bc183765c54a9f3b3b4f20f33eb0a0cd20a6e73..0000000000000000000000000000000000000000 --- a/modules/gui/src/sequence_viewer/sequence_viewer_base.hh +++ /dev/null @@ -1,99 +0,0 @@ -//------------------------------------------------------------------------------ -// This file is part of the OpenStructure project <www.openstructure.org> -// -// Copyright (C) 2008-2010 by the OpenStructure authors -// -// This library is free software; you can redistribute it and/or modify it under -// the terms of the GNU Lesser General Public License as published by the Free -// Software Foundation; either version 3.0 of the License, or (at your option) -// any later version. -// This library is distributed in the hope that it will be useful, but WITHOUT -// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -// details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this library; if not, write to the Free Software Foundation, Inc., -// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -//------------------------------------------------------------------------------ -#ifndef OST_GUI_SEQUENCE_VIEWER_BASE_HH -#define OST_GUI_SEQUENCE_VIEWER_BASE_HH -/* - Author: Marco Biasini - */ - -#include <ost/gui/sequence_viewer/sequence_item.hh> -#include <ost/gui/sequence_viewer/sequence_scene.hh> - -#include <ost/gui/widget.hh> - -#include <QGraphicsView> - -namespace ost { namespace gui { - -class SequenceSearchBar; - -/// \brief base class for sequence viewers -/// -/// subclassed by AlignmentViewer and SequenceViewer -class DLLEXPORT_OST_GUI SequenceViewerBase : public Widget { - Q_OBJECT -public: - typedef enum { - DENSE, - LOOSE, - } Style; - - typedef enum { - COLUMN, - ROW - } SelMode; -public: - SequenceViewerBase(QWidget* parent=NULL); - void SetDisplayStyle(Style style); - - void SetSelMode(SelMode mode); - - SelMode GetSelMode() const; - Style GetDisplayStyle() const; - - /// \brief add sequence - /// - /// issue: should we copy the sequence object to avoid weird side-effects? - void AddSequence(SequenceItem* seq); - - /// \brief remove sequence - void RemoveSequence(SequenceItem* seq); - - /// \brief select columns in all sequences - void SelectColumns(std::vector<bool>& selected_cols); - - /// \brief select columns in sequence - void SelectColumns(SequenceItem* seq, std::vector<bool>& selected_cols); - /// \brief get length of longest sequence including gaps - int GetLongestSequenceLength() const; - /// \brief remove all sequences - void Clear(); - - virtual bool Restore(const QString& prefix); - virtual bool Save(const QString& prefix); -public slots: - /// \brief clear selection - void ClearSelection(); - - /// \internal - void OnSearchBarUpdate(const QString&, bool, int); - - /// \brief show sequence search bar - void FindInSequence(); - -private: - Style style_; - SelMode sel_mode_; - SequenceScene* scene_; - SequenceSearchBar* search_bar_; - QGraphicsView* view_; -}; - -}} -#endif diff --git a/modules/gui/src/sequence/tick_painter.cc b/modules/gui/src/sequence_viewer/tick_painter.cc similarity index 100% rename from modules/gui/src/sequence/tick_painter.cc rename to modules/gui/src/sequence_viewer/tick_painter.cc diff --git a/modules/gui/src/sequence/tick_painter.hh b/modules/gui/src/sequence_viewer/tick_painter.hh similarity index 100% rename from modules/gui/src/sequence/tick_painter.hh rename to modules/gui/src/sequence_viewer/tick_painter.hh diff --git a/modules/gui/src/sequence/title_row.cc b/modules/gui/src/sequence_viewer/title_row.cc similarity index 89% rename from modules/gui/src/sequence/title_row.cc rename to modules/gui/src/sequence_viewer/title_row.cc index 39013b3d7fda9a5df35d377ed3411220c24e2800..727aa0239b86a8e3eff2bba67e326efb0f3ea428 100644 --- a/modules/gui/src/sequence/title_row.cc +++ b/modules/gui/src/sequence_viewer/title_row.cc @@ -77,10 +77,11 @@ Qt::ItemFlags TitleRow::Flags(int column) const void TitleRow::DoubleClicked(int column) { if(this->parent()){ - SequenceModel* model = qobject_cast<SequenceModel*>(this->parent()->parent()); - int rows = model->rowCount()-1; - QItemSelection add = QItemSelection(model->index(1,column),model->index(rows,column)); - model->SelectionChanged(add,QItemSelection()); + if(SequenceModel* model = qobject_cast<SequenceModel*>(this->parent()->parent())){ + int rows = model->rowCount()-1; + QItemSelection add = QItemSelection(model->index(1,column),model->index(rows,column)); + model->SelectionChanged(add,QItemSelection()); + } } } diff --git a/modules/gui/src/sequence/title_row.hh b/modules/gui/src/sequence_viewer/title_row.hh similarity index 100% rename from modules/gui/src/sequence/title_row.hh rename to modules/gui/src/sequence_viewer/title_row.hh diff --git a/modules/img/alg/doc/alg.rst b/modules/img/alg/doc/alg.rst new file mode 100644 index 0000000000000000000000000000000000000000..3e0f673dedc821d52a781f873d5d21d615f00794 --- /dev/null +++ b/modules/img/alg/doc/alg.rst @@ -0,0 +1,67 @@ +:mod:`~ost.img.alg` - Image Processing Algorithms +================================================================================ + +.. module:: ost.img.alg + :synopsis: Image processing algorithms + +Usage of Image Algorithms +-------------------------------------------------------------------------------- + +Image algorithms are objects. To execute them, the algorithms are applied to an +image by passing it to the :meth:`ost.img.ImageHandle.Apply` or +:meth:`ost.img.ImageHandle.ApplyIP` method: + +.. code-block:: python + + image=img.CreateImage(img.Size(200, 200)) + fft_image=image.Apply(img.alg.FFT()) + image.ApplyIP(img.alg.FFT()) + + +.. class:: FFT + + Fast Fourier Transforms the image. The FFT algorithms is aware of the + image's domain. The following rules apply: + + * SPATIAL -> HALF_FREQUENCY + * HALF_FREQUENCY -> SPATIAL + * FREQUENCY -> COMPLEX_SPATIAL + * COMPLEX_SPATIAL -> FREQUENCY + +.. class:: GaussianFilter(sigma=1.0) + + Applies a gaussian filter to the supplied image. Sigma is given in pixels. + + Implemented after I.T.Young, L.J. van Vliet,"Recursive implementation of the + Gaussian filter", Signal Processing, 44(1995), 139-151 + +Filters in Fourier Space +-------------------------------------------------------------------------------- + +The following filters operate in Fourier Space. If the image they are applied on is in spatial domain, they will first be converted to frequency domain and then converted back after the filter has been applied. + +.. class:: LowpassFilter(freq_limit) + + Filters an image by masking out frequencies higher than + `freg_limit`. + + .. method:: GetLimit() + + Returns the frequency limit + + .. method:: SetLimit(freq) + + Set the frequency limit + +.. class:: HighpassFilter + + Filters an image by masking out frequences lower than `freq_limit` + + .. method:: GetLimit() + + Returns the frequency limit + + .. method:: SetLimit(freq) + + Set the frequency limit + \ No newline at end of file diff --git a/modules/img/alg/src/highest_peak_search_3d.cc b/modules/img/alg/src/highest_peak_search_3d.cc index aaedb099410dbf3e292d3430037ee32c1fd9158a..eeedd054fcd181a6a3a4eee3f03a32a1a9af38e0 100644 --- a/modules/img/alg/src/highest_peak_search_3d.cc +++ b/modules/img/alg/src/highest_peak_search_3d.cc @@ -74,42 +74,43 @@ namespace detail { bool insert=true; bool remove_smaller=false; img::PeakList::iterator min_it; + if(!list_.empty()) { min_it = list_.begin(); - } - for(img::PeakList::iterator it=list_.begin();it!=list_.end();++it) - { - if(it->GetValue() < min_it->GetValue()) min_it = it; - if (it->GetValue() >= cand_peak.GetValue() && detail::is_within(cand_peak, *it, exclusion_radius_)) { - insert=false; - } else if (cand_peak.GetValue() >= it->GetValue() && detail::is_within(cand_peak, *it, exclusion_radius_)) { - remove_smaller=true; + for(img::PeakList::iterator it=list_.begin();it!=list_.end();++it) + { + if(it->GetValue() < min_it->GetValue()) min_it = it; + if (it->GetValue() >= cand_peak.GetValue() && detail::is_within(cand_peak, *it, exclusion_radius_)) { + insert=false; + } else if (cand_peak.GetValue() >= it->GetValue() && detail::is_within(cand_peak, *it, exclusion_radius_)) { + remove_smaller=true; + } } - } - if (!insert) return false; + if (!insert) return false; - if (cand_peak.GetValue() < min_it->GetValue()) { - return false; - } + if (cand_peak.GetValue() < min_it->GetValue()) { + return false; + } - if (remove_smaller) - { - img::PeakList::iterator new_end = remove_if(list_.begin(),list_.end(), - detail::is_smaller_and_within_radius(cand_peak,exclusion_radius_)); - list_.erase(new_end,list_.end()); - } + if (remove_smaller) + { + img::PeakList::iterator new_end = remove_if(list_.begin(),list_.end(), + detail::is_smaller_and_within_radius(cand_peak,exclusion_radius_)); + list_.erase(new_end,list_.end()); + } - if (list_.size() == max_num_peaks_) { - list_.erase(min_it); + if (list_.size() == max_num_peaks_) { + list_.erase(min_it); + } } list_.push_back(cand_peak); return true; } - //! Gets list of peaks from collector + //! Gets list of peaks from collector img::PeakList GetPeakList() const { return list_; } //! Clears the peak list removing all peaks in the list @@ -117,7 +118,7 @@ namespace detail { private: - img::PeakList list_; + img::PeakList list_; unsigned int max_num_peaks_; int exclusion_radius_; @@ -133,8 +134,13 @@ template <typename T, class D> LOG_VERBOSE(" max number of peaks: " << max_num_peaks_ << std::endl); LOG_VERBOSE(" exclusion radius: " << exclusion_radius_ << std::endl); LOG_VERBOSE(" threshold: " << threshold_ << std::endl); - - if(ext_list_.size()==0) + + if (max_num_peaks_ < 1) + { + throw Error("Error: Maximum number of peaks smaller than 1. Cannot create peak list"); + } + + if(ext_list_.size()==0) { LOG_VERBOSE(" excluded regions: none" << std::endl); } diff --git a/modules/img/alg/src/histogram.hh b/modules/img/alg/src/histogram.hh index f974247da64b4f51f1c8d5d87afc1e59b608f022..7805d40fcb86740c0d85eadc35d97111f17eed75 100644 --- a/modules/img/alg/src/histogram.hh +++ b/modules/img/alg/src/histogram.hh @@ -17,6 +17,8 @@ // along with this library; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA //------------------------------------------------------------------------------ +#ifndef OST_IMG_ALG_HISTOGRAM_HH +#define OST_IMG_ALG_HISTOGRAM_HH /* Author: Ansgar Philippsen @@ -75,3 +77,5 @@ typedef ImageStateNonModAlgorithm<HistogramBase> Histogram; OST_IMG_ALG_EXPLICIT_INST_DECL(class,ImageStateNonModAlgorithm<alg::HistogramBase>) }} // namespaces + +#endif diff --git a/modules/img/alg/tests/test_discrete_shrink.cc b/modules/img/alg/tests/test_discrete_shrink.cc index 30be5ab060e9f12513becff5bf43fa86b0c61b80..337a15736d7388f0f61d36890363acb4d2c63a0a 100644 --- a/modules/img/alg/tests/test_discrete_shrink.cc +++ b/modules/img/alg/tests/test_discrete_shrink.cc @@ -53,7 +53,7 @@ void test() h.GetReal(p2+Point(1,0))+ h.GetReal(p2+Point(0,1))+ h.GetReal(p2+Point(1,1))); - BOOST_CHECK(std::fabs(sm-rh.GetReal(it))<1e-10); + BOOST_CHECK_SMALL(Real(std::fabs(sm-rh.GetReal(it))),Real(1e-7)); } } diff --git a/modules/img/alg/tests/test_filter.cc b/modules/img/alg/tests/test_filter.cc index d64b2603839f644e8bcb35cfe6dde26637f93f6d..400bc1bd451d1443928cab5817a0b6da565c7979 100644 --- a/modules/img/alg/tests/test_filter.cc +++ b/modules/img/alg/tests/test_filter.cc @@ -21,8 +21,9 @@ /* Author: Ansgar Philippsen */ - +#define BOOST_TEST_DYN_LINK #include <boost/test/unit_test.hpp> + #include <iostream> #include <ost/img/image.hh> #include <ost/img/alg/filter.hh> @@ -450,9 +451,9 @@ void FourierFiltersTest() } -DLLEXPORT_IMG_ALG boost::unit_test::test_suite::test_suite* init_unit_test_suite( int argc, char* argv[] ) +boost::unit_test::test_suite* init_unit_test_suite( int argc, char* argv[] ) { - boost::unit_test::test_suite::test_suite* test = BOOST_TEST_SUITE( "FiltersTest" ); + boost::unit_test::test_suite* test = BOOST_TEST_SUITE( "FiltersTest" ); test->add( BOOST_TEST_CASE( &LineIterator1DTest ) ); test->add( BOOST_TEST_CASE( &LineIterator2DTest ) ); diff --git a/modules/img/alg/tests/test_utils.hh b/modules/img/alg/tests/test_utils.hh index 0eb527642969ec65b7b8087ecb7b9f91666f59e8..26687e16476671fad1e05cae46bc6b755a5f5ef8 100644 --- a/modules/img/alg/tests/test_utils.hh +++ b/modules/img/alg/tests/test_utils.hh @@ -27,7 +27,8 @@ #include <iostream> -#include <boost/test/test_tools.hpp> +#define BOOST_TEST_DYN_LINK +#include <boost/test/unit_test.hpp> //#include <img/base.hh> #include <ost/img/image_state.hh> diff --git a/modules/img/alg/tests/tests.hh b/modules/img/alg/tests/tests.hh index 46ff55ebf4df6296cb0bce71c9745ff731c3641a..97b66c8a953b84e588f055b6685125e604a47082 100644 --- a/modules/img/alg/tests/tests.hh +++ b/modules/img/alg/tests/tests.hh @@ -22,5 +22,6 @@ Author: Ansgar Philippsen */ +#define BOOST_TEST_DYN_LINK #include <boost/test/unit_test.hpp> using boost::unit_test_framework::test_suite; diff --git a/modules/img/base/doc/img.rst b/modules/img/base/doc/img.rst new file mode 100644 index 0000000000000000000000000000000000000000..53243c9042291e6151667d154c4c411d3a543f8b --- /dev/null +++ b/modules/img/base/doc/img.rst @@ -0,0 +1,186 @@ +:mod:`~ost.img` Images and Density Maps +================================================================================ + +.. module:: ost.img + :synopsis: Images and density maps + +Introduction : The ImageHandle +-------------------------------------------------------------------------------- + +OpenStructure offers extensive processing capabilities for planar 2d images and +3d maps using the img module. Images are manipulated through the use of +dox[ost::img::ImageHandle|ImageHandles]. + +ImageHandles provide a clean and efficient interface to interact with images and +maps. An :class:`ImageHandle` can store an image in either real ('SPATIAL') or +Fourier ('FREQUENCY') space and always keep track of the currently active +domain. This means,for example that one can apply a Fourier Transformation to an +ImageHandle containing a 'SPATIAL' image and the ImageHandle will correctly +identify the new active domain as 'FREQUENCY'. The ImageHandle also understands, +for example, that applying a Fourier Transform to a centrosymmetric 'FREQUENCY' +image results in a real 'SPATIAL' image, but applying it to a +non-centrosymmetric one results in a complex 'SPATIAL' image. + +Furthermore, the ImageHandle will make sure that real and Fourier space +information about the image are always in sync. If, for example, the pixel +sampling is changed while the current active domain is real space, the pixel +sampling in Fourier space will be adjusted accordingly, and vice versa. + +Moreover, the ImageHandle allows the extraction of both complex and real numeric +values from images in any active domain. If the domain is complex in nature, but +a real numeric value is requested, the amplitude of the complex number will be +returned. If the numerical nature of the domain is real and a complex number is +requested, the complex part will be set to 0. + +Creating and visualizing ImageHandles +-------------------------------------------------------------------------------- +As a first step, enter the following lines in the OpenStructure python console: + + .. code-block:: python + + im=img.CreateImage(img.Size(200,200)) + +This will create an empty, 2D image, with a height and width of 200 pixels, whose +origin (ie the pixel with the coordinates <0,0>) is in the top-left corner. + + .. code-block:: python + + v=gui.CreateDataViewer(im) + +A viewer window will pop up (see below), showing a white frame on a black background. +The inner area of the white frame is the image, which is empty. + +Reading and writing into an image +------------------------------------------------------------------------------- + +Data can be read and written from and into an image using the following commands: + + .. code-block:: python + + # writes the real value 23.4 into pixel 10,10 + im.SetReal(img.Point(10,10),23.4) + # reads the value in pixel 10,10 + val=im.GetReal(img.Point(10,10)) + +The complex equivalents are also available + + .. code-block:: python + + # writes the complex value value 2+3j into pixel 10,10 + im.SetComplex(img.Point(10,10),2+3j) + # reads the value in pixel 10,10 + val=im.GetComplex(img.Point(10,10)) + +The image knows in which domain it is, and will adjust the type of data being written +accordingly. For example, if one writes a complex value in a 'SPATIAL' image, the value +will be automatically converted to a real one by taking the amplitude of the complex number +On the other hand, if one writes a real value in a 'FREQUENCY' image, the value is automatically +converted to complex by setting the imaginary part to 0. + +## Applying algorithms + +Let us fill the image with random values. + + .. code-block:: python + + rand_alg = img.alg.Randomize() # create algorithm object + im.ApplyIP( rand_alg ) # apply algorithm object in-place + +As you can see, applying an algorithm is conceptually a two-step process. First, +an instance of an algorithm class is created, yielding an algorithm object (in +this case 'rand\_alg'). In a second step, the algorithm object is applied to an +image, either in-place, modifying the image, or out-of-place, leaving the +original image untouched, and returning the result as a new image. Note that the +in-place/out-of-place logic is decoupled from the algorithm object. + +Now that we have some (noisy) data present, let us run another algorithm, this +time a Gaussian filter with a sigma of 4 pixel. + + .. code-block:: python + + im.ApplyIP( img.alg.GaussianFilter(4.0) ) # apply temporary algorithm object in-place + +As you can see, it is not always necessary to create an independent algorithm +instance first, in many cases a temporary object will suffice (this applies to +the randomization algorithm as well, 'im.ApplyIP(alg.Randomize())' would have +been fine). However, when used this way, the algorithm class will cease to exist +as soon as the algorithm is applied. This can be important if the algorithm +stores some values that need to be recovered later. For example: + + .. code-block:: python + + stat=img.alg.Stat() + im.ApplyIP(stat) + mean=stat.GetMean() + +Algorithms are stateful objects and can store values. The 'Stat' algorithm +computes basic statistics about the image it is applied on (maximum and minimum +values, standard deviations, etc). The data are stored within the algorithm +instance and can be recovered using the algorithm's methods. It would obviously +make very little sense not to create an instance of the 'Stat' algorithm. When +the algorithms ceases to exist, all information would be lost. + +Applying a Fourier Transform +-------------------------------------------------------------------------------- + +An image is Fourier-transformed using the 'img.alg.FFT()' algorithm object: + + .. code-block:: python + + im=io.LoadImage("imagename.tif") # load the image + # create an instance of the fft algorithm object + fft=img.alg.FFT() + # do the actual Fourier transformation + im_ft=im.Apply(fft) + # back-transform + im2 = im_ft.Apply(fft) + # if this is run from within the dng graphical frontend, open viewers to + # look at the images + gui.CreateDataViewer(im) + gui.CreateDataViewer(im_ft) + gui.CreateDataViewer(im2) + +It is not really necessary to use the 'fft' variable to store the 'im.alg.FFT()' +instance, a temporary object can be used, since the 'FFT' algorithm object is stateless. In addition, the algorithm can be applied in-place to avoid the +creation of a second image: + + .. code-block:: python + + im=io.LoadImage("imagename.tif") # load the image + # do the actual Fourier transformation, in-place using temporary object + im.ApplyIP(alg.FFT()) + # repeating this command will do the back-transform + im.ApplyIP(alg.FFT()) + +As said before, the 'alg.FFT()' algorithm does not require a direction to be given, this is implicitly +determined by the active domain of the underlying image state: a 'SPATIAL' image will always be +transformed to the 'FREQUENCY' domain, and vice-versa. + +Extracting and Pasting Images +-------------------------------------------------------------------------------- + +An image can be extracted and pasted into another image using the 'Extract()' +and 'Paste()' member functions: + + .. code-block:: python + + # load the image + im=io.LoadImage("imagename.tif") + # generate a subimage from the region going from (10,10) to (30,30) + im2=im.Extract(img.Extent(img.Point(10,10),img.Point(30,30))) + # generate an empty image with the same size as the original image + im3=img.CreateImage(im.GetExtent()) + # paste the subimage into the empty image + im3.Paste(im2) + +Note that the extent is fully honored for the paste operation, i.e. only the +region where the pasted-to and the pasted-in image overlap will be affected. + + + + .. + | | | | + |:-------------------------------------------------:|:-------------------------------------------------------------------:|:------------------------------------------------------------------------:| + |![Empty Image] (docs/tut/dv1.jpg "Empty Image") | ![After Randomization] (docs/tut/dv2.jpg "After Randomization") | ![After Gaussian Filtering] (docs/tut/dv3.jpg "After Randomization") | + |Empty Image | After Randomization | After Gaussian Filtering | + \ No newline at end of file diff --git a/modules/img/base/pymod/export_mask.cc b/modules/img/base/pymod/export_mask.cc index 6db4cf05e80dd066460fed2215a83c58444a0396..3385d8ffc69061639aa221442dc24f9d3da4d988 100644 --- a/modules/img/base/pymod/export_mask.cc +++ b/modules/img/base/pymod/export_mask.cc @@ -26,6 +26,7 @@ using namespace boost::python; #include <ost/img/mask.hh> +#include <ost/img/mask_info_convert.hh> namespace ost { namespace img { @@ -100,5 +101,7 @@ void export_Mask() def("Mask",mask2); def("Mask",mask3); def("Mask",mask4); + def("InfoToMask",InfoToMask); + def("MaskToInfo",MaskToInfo); } diff --git a/modules/img/base/src/CMakeLists.txt b/modules/img/base/src/CMakeLists.txt index 0d0e7e47a5b42c6e028275471a66928d34d54c2c..97ea2ed0b32297cf7e5298ec975d221a956da806 100644 --- a/modules/img/base/src/CMakeLists.txt +++ b/modules/img/base/src/CMakeLists.txt @@ -29,6 +29,7 @@ extent_mask.cc spherical_mask.cc mask_op.cc circle_mask.cc +mask_info_convert.cc image_list.cc physical_units.cc progress.cc @@ -86,6 +87,7 @@ spherical_mask.hh mask_op.hh mask.hh circle_mask.hh +mask_info_convert.hh image_list.hh physical_units.hh progress.hh @@ -105,4 +107,4 @@ module(NAME img SOURCES "${OST_IMG_SOURCES}" HEADERS ${OST_IMG_RASTER_IMAGE_HEADERS} IN_DIR raster_image ${OST_IMG_IMAGE_STATE_HEADERS} IN_DIR image_state ${OST_IMG_HEADERS} - DEPENDS_ON geom base) + DEPENDS_ON geom base info) diff --git a/modules/img/base/src/function_base.hh b/modules/img/base/src/function_base.hh index efb654bd21874c9ad75af499c57d45653d2063fa..6360ac36b58c6286b78794784ad862c9651226eb 100644 --- a/modules/img/base/src/function_base.hh +++ b/modules/img/base/src/function_base.hh @@ -27,6 +27,7 @@ #ifndef IMG_FUNCTION_BASE_H #define IMG_FUNCTION_BASE_H +#include "module_config.hh" #include "data.hh" #include "data_observer.hh" #include "observable.hh" diff --git a/modules/img/base/src/image_state/image_state_impl.cc b/modules/img/base/src/image_state/image_state_impl.cc index 190728a105dd5977f6d85640a8f80ff83584c7bb..020d216511c10c955143d04f3376452102088aaf 100644 --- a/modules/img/base/src/image_state/image_state_impl.cc +++ b/modules/img/base/src/image_state/image_state_impl.cc @@ -72,7 +72,8 @@ template <typename T, class D> ImageStateImpl<T,D>::ImageStateImpl(const ImageStateImpl<T,D>& s): domain_(s.domain_), data_(s.data_), - sampling_(s.sampling_) + sampling_(s.sampling_), + absolute_origin_(s.absolute_origin_) { sampling_.SetDomain(domain_.GetDomain()); } @@ -85,6 +86,7 @@ ImageStateImpl<T,D>& ImageStateImpl<T,D>::operator=(const ImageStateImpl<T,D>& s domain_=s.domain_; data_=s.data_; // copy sampling_=s.sampling_; + absolute_origin_=s.absolute_origin_; sampling_.SetDomain(domain_.GetDomain()); } return *this; diff --git a/modules/img/base/src/image_state/image_state_visitor.hh b/modules/img/base/src/image_state/image_state_visitor.hh index 7fc7c7e502a780db4eeb9c39b96a090599f9484d..408941d9c64ab1c2e331f76bc1484451d228a2d2 100644 --- a/modules/img/base/src/image_state/image_state_visitor.hh +++ b/modules/img/base/src/image_state/image_state_visitor.hh @@ -299,7 +299,7 @@ public: See also common algorithms, e.g. img::alg::Stat */ template <class FNC> -class DLLEXPORT_OST_IMG_BASE ImageStateNonModVisitor: public FNC, public ImageStateNonModVisitorBase { +class DLLEXPORT ImageStateNonModVisitor: public FNC, public ImageStateNonModVisitorBase { public: IMAGE_STATE_VISITOR_CTOR_ADAPTERS(ImageStateNonModVisitor) @@ -354,7 +354,7 @@ public: */ template <class FNC> -class DLLEXPORT_OST_IMG_BASE ImageStateModIPVisitor: public FNC, public ImageStateModIPVisitorBase { +class DLLEXPORT ImageStateModIPVisitor: public FNC, public ImageStateModIPVisitorBase { public: IMAGE_STATE_VISITOR_CTOR_ADAPTERS(ImageStateModIPVisitor) @@ -461,7 +461,7 @@ public: */ template <class FNC> -class DLLEXPORT_OST_IMG_BASE ImageStateModOPVisitor: public FNC, public ImageStateModOPVisitorBase { +class DLLEXPORT ImageStateModOPVisitor: public FNC, public ImageStateModOPVisitorBase { public: IMAGE_STATE_VISITOR_CTOR_ADAPTERS(ImageStateModOPVisitor) diff --git a/modules/img/base/src/mask_info_convert.cc b/modules/img/base/src/mask_info_convert.cc new file mode 100644 index 0000000000000000000000000000000000000000..de40f80a4733b605be1543f61dee6fec88d0ad56 --- /dev/null +++ b/modules/img/base/src/mask_info_convert.cc @@ -0,0 +1,227 @@ +//------------------------------------------------------------------------------ +// This file is part of the OpenStructure project <www.openstructure.org> +// +// Copyright (C) 2008-2010 by the OpenStructure authors +// Copyright (C) 2003-2010 by the IPLT authors +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation; either version 3.0 of the License, or (at your option) +// any later version. +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +//------------------------------------------------------------------------------ + +/* + Authors: Andreas Schenk, Ansgar Philippsen +*/ + +#include <stack> + +#include <ost/info/info_visitor.hh> +#include <ost/info/info.hh> +#include "mask_info_convert.hh" +#include "polygon_mask.hh" +#include "circle_mask.hh" +#include "extent_mask.hh" +#include "composite_mask.hh" +#include "inverted_mask.hh" +#include "spherical_mask.hh" +#include "mask_visitor.hh" + +namespace ost{ namespace img { + +namespace { + + + +class PolygonInfoVisitor: public info::InfoConstVisitor +{ +public: + PolygonInfoVisitor(): + p_() + {} + + Polygon2 GetPolygon() const {return p_;} + + virtual bool VisitGroup(const info::InfoGroup& group) + { + if(group.GetName()=="Polygon"){ + return true; + } else if(group.GetName()=="Node"){ + p_.AddNode(geom::Vec2(group.GetItem("x").AsFloat(), + group.GetItem("y").AsFloat())); + return false; + } + return true; + } + + virtual void VisitGroupFinish(const info::InfoGroup& group) + {} + +private: + Polygon2 p_; +}; + +// this is used recursively +class MaskInfoVisitor: public info::InfoConstVisitor +{ +public: + MaskInfoVisitor(): + mask_list_() + {} + + std::vector<MaskPtr> GetMaskList() const {return mask_list_;} + + virtual bool VisitGroup(const info::InfoGroup& group) + { + String name=group.GetName(); + if(name=="Composite"){ + String opname=group.GetItem("Operator").GetValue(); + MaskInfoVisitor miv; + group.Apply(miv,false); // subgroups + std::vector<MaskPtr> mpl = miv.GetMaskList(); + mask_list_.push_back(MaskPtr(new CompositeMask(mpl[0],mpl[1],opname))); + return false; + }else if(name=="Invert"){ + MaskInfoVisitor miv; + group.Apply(miv,false); // subgroups + std::vector<MaskPtr> mpl = miv.GetMaskList(); + mask_list_.push_back(MaskPtr(new InvertedMask(mpl[0]))); + return false; + }else if(name=="Circle"){ + Circle2 c; + c.SetRadius(group.GetItem("Radius").AsFloat()); + c.SetCenter(geom::Vec2(group.GetItem("Center/x").AsFloat(), + group.GetItem("Center/y").AsFloat())); + mask_list_.push_back(MaskPtr(new CircleMask(c))); + return false; + }else if(name=="Polygon"){ + PolygonInfoVisitor pvis; + group.Apply(pvis); + mask_list_.push_back(MaskPtr(new PolygonMask(pvis.GetPolygon()))); + return false; + }else if(name=="Extent"){ + Extent e(Point(group.GetItem("Start/x").AsInt(), + group.GetItem("Start/y").AsInt()), + Point(group.GetItem("End/x").AsInt(), + group.GetItem("End/y").AsInt())); + mask_list_.push_back(MaskPtr(new ExtentMask(e))); + return false; + }else if(name=="Sphere"){ + Sphere s; + s.SetRadius(group.GetItem("Radius").AsFloat()); + s.SetOrigin(geom::Vec3(group.GetItem("Origin/x").AsFloat(), + group.GetItem("Origin/y").AsFloat(), + group.GetItem("Origin/z").AsFloat())); + mask_list_.push_back(MaskPtr(new SphericalMask(s))); + return false; + } + return true; + } + + virtual void VisitGroupFinish(const info::InfoGroup& group) + { + } + +private: + std::vector<MaskPtr> mask_list_; +}; + + +// mask visitor for mask->info conversion +class MaskToInfoVisitor: public MaskVisitor +{ + typedef std::stack<info::InfoGroup> InfoGroupStack; +public: + MaskToInfoVisitor(info::InfoGroup& g): + igs_() + { + igs_.push(g); + } + virtual void VisitCircleMask(CircleMask& m) + { + info::InfoGroup cg=igs_.top().CreateGroup("Circle"); + info::InfoGroup centerg=cg.CreateGroup("Center"); + centerg.CreateItem("x","").SetFloat(m.GetCenter()[0]); + centerg.CreateItem("y","").SetFloat(m.GetCenter()[1]); + cg.CreateItem("Radius","").SetFloat(m.GetRadius()); + } + virtual void VisitCompositeMask(CompositeMask& m) + { + info::InfoGroup compg=igs_.top().CreateGroup("Composite"); + compg.CreateItem("Operator",m.GetOperatorName()); + igs_.push(compg); + } + virtual void VisitCompositeMaskFinish(CompositeMask& m) + { + igs_.pop(); + } + virtual void VisitExtentMask(ExtentMask& m) + { + info::InfoGroup extg=igs_.top().CreateGroup("Extent"); + info::InfoGroup startg=extg.CreateGroup("Start"); + startg.CreateItem("x","").SetInt(m.GetStart()[0]); + startg.CreateItem("y","").SetInt(m.GetStart()[1]); + info::InfoGroup endg=extg.CreateGroup("End"); + endg.CreateItem("x","").SetInt(m.GetEnd()[0]); + endg.CreateItem("y","").SetInt(m.GetEnd()[1]); + } + virtual void VisitInvertedMask(InvertedMask& m) + { + info::InfoGroup invertg=igs_.top().CreateGroup("Invert"); + igs_.push(invertg); + } + virtual void VisitInvertedMaskFinish(InvertedMask& m) + { + igs_.pop(); + } + virtual void VisitPolygonMask(PolygonMask& m) + { + info::InfoGroup polyg=igs_.top().CreateGroup("Polygon"); + for(unsigned int nn=0;nn<m.GetNodeCount();++nn) { + info::InfoGroup nodeg=polyg.CreateGroup("Node"); + geom::Vec2 node=m.GetNode(nn); + nodeg.CreateItem("x","").SetFloat(node[0]); + nodeg.CreateItem("y","").SetFloat(node[1]); + } + } + virtual void VisitSphericalMask(SphericalMask& m) + { + info::InfoGroup cg=igs_.top().CreateGroup("Sphere"); + info::InfoGroup centerg=cg.CreateGroup("Origin"); + centerg.CreateItem("x","").SetFloat(m.GetOrigin()[0]); + centerg.CreateItem("y","").SetFloat(m.GetOrigin()[1]); + centerg.CreateItem("z","").SetFloat(m.GetOrigin()[2]); + cg.CreateItem("Radius","").SetFloat(m.GetRadius()); + } +private: + InfoGroupStack igs_; +}; + +} // anon ns + +MaskPtr DLLEXPORT InfoToMask(const info::InfoGroup& g) +{ + MaskInfoVisitor vis; + g.Apply(vis); + std::vector<MaskPtr> mlist = vis.GetMaskList(); + if(!mlist.empty()) { + return mlist[0]; + } + return MaskPtr(); +} + +void MaskToInfo(const MaskPtr& mptr ,info::InfoGroup& g) +{ + MaskToInfoVisitor vis(g); + mptr->Apply(vis); +} + +}} //ns diff --git a/modules/img/base/src/mask_info_convert.hh b/modules/img/base/src/mask_info_convert.hh new file mode 100644 index 0000000000000000000000000000000000000000..04a01eac42e211c08a18bc2f28c6897fce371bfb --- /dev/null +++ b/modules/img/base/src/mask_info_convert.hh @@ -0,0 +1,38 @@ +//------------------------------------------------------------------------------ +// This file is part of the OpenStructure project <www.openstructure.org> +// +// Copyright (C) 2008-2010 by the OpenStructure authors +// Copyright (C) 2003-2010 by the IPLT authors +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation; either version 3.0 of the License, or (at your option) +// any later version. +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +//------------------------------------------------------------------------------ + +/* + Authors: Andreas Schenk, Ansgar Philippsen +*/ + +#ifndef MASK_INFO_CONVERT_HH_ +#define MASK_INFO_CONVERT_HH_ + +#include <ost/info/info_group.hh> +#include "mask_base_fw.hh" + +namespace ost { namespace img { + +MaskPtr DLLEXPORT InfoToMask(const info::InfoGroup& g); +void DLLEXPORT MaskToInfo(const MaskPtr& mptr, info::InfoGroup& g); + +}} //ns + +#endif /*MASK_INFO_CONVERT_HH_*/ diff --git a/modules/img/base/src/null_function.hh b/modules/img/base/src/null_function.hh index 29087c848b96ea83f105f46e7419a78c1908d63c..23243824308ef51ebccc83e7742e9b824abda4f6 100644 --- a/modules/img/base/src/null_function.hh +++ b/modules/img/base/src/null_function.hh @@ -27,6 +27,7 @@ #ifndef IMG_NULL_FUNCTION_H #define IMG_NULL_FUNCTION_H +#include "module_config.hh" #include "function_base.hh" namespace ost { namespace img { @@ -36,7 +37,7 @@ namespace ost { namespace img { Implements Function interface, will always return zero */ -class DLLEXPORT_OST_IMG_BASE NullFunction: public Function { +class DLLEXPORT NullFunction: public Function { public: NullFunction(): Function(SPATIAL) @@ -47,6 +48,8 @@ public: virtual Real GetIntpolReal(const Vec3& v) const {return 0.0;} virtual Complex GetIntpolComplex(const Vec3& v) const {return Complex(0.0,0.0);} + + virtual ~NullFunction(){}; }; }} // namespace diff --git a/modules/img/base/src/observable.hh b/modules/img/base/src/observable.hh index 77c00411005a728c07fa6e822e277515ef5e7efc..831d1c8ea0683f3a2354bdbc3d4368cfc1ae8d91 100644 --- a/modules/img/base/src/observable.hh +++ b/modules/img/base/src/observable.hh @@ -39,7 +39,7 @@ namespace ost { namespace img { and ObserverUpdate */ template <class T> -class DLLEXPORT_OST_IMG_BASE Observable { +class DLLEXPORT Observable { typedef std::list<T *> ObserverList; typedef typename ObserverList::iterator ObserverIter; typedef typename ObserverList::const_iterator ObserverConstIter; diff --git a/modules/img/base/tests/CMakeLists.txt b/modules/img/base/tests/CMakeLists.txt index b51491b9dc147857dedca6bc811691baa756f115..420287a47a44f863db056cb9ce17062c24e9f95c 100644 --- a/modules/img/base/tests/CMakeLists.txt +++ b/modules/img/base/tests/CMakeLists.txt @@ -17,6 +17,6 @@ tests.cc ost_unittest(img "${OST_IMG_BASE_UNIT_TESTS}") -if(NOT WIN32) + target_link_libraries(img_tests ost_img_alg) -endif() + diff --git a/modules/img/base/tests/test_data.hh b/modules/img/base/tests/test_data.hh index 1e72598ed44f55149966c54c00db0cb97c3774ce..34f80f1d8f5b2feeec966200c3e97195637a5c1e 100644 --- a/modules/img/base/tests/test_data.hh +++ b/modules/img/base/tests/test_data.hh @@ -25,6 +25,7 @@ #ifndef IMG_TEST_DATA_H #define IMG_TEST_DATA_H +#define BOOST_TEST_DYN_LINK #include <boost/test/unit_test.hpp> using boost::unit_test_framework::test_suite; diff --git a/modules/img/base/tests/test_domains.cc b/modules/img/base/tests/test_domains.cc index 05cf10217f3faaf6a448618441d8f4bf56f32af9..8a8d22935068968bc0b6e3359cdaeac11619f3a3 100644 --- a/modules/img/base/tests/test_domains.cc +++ b/modules/img/base/tests/test_domains.cc @@ -24,6 +24,7 @@ #include <sstream> +#define BOOST_TEST_DYN_LINK #include <boost/test/unit_test.hpp> using boost::unit_test_framework::test_suite; diff --git a/modules/img/base/tests/test_extent.hh b/modules/img/base/tests/test_extent.hh index 4d452b217fcdf65fa3575a2f6e97bba4bf614143..75eb950c4fb1ca9bfef7856eb37cef9f44488e74 100644 --- a/modules/img/base/tests/test_extent.hh +++ b/modules/img/base/tests/test_extent.hh @@ -25,6 +25,7 @@ #ifndef IMG_TEST_EXTENT_H #define IMG_TEST_EXTENT_H +#define BOOST_TEST_DYN_LINK #include <boost/test/unit_test.hpp> using boost::unit_test_framework::test_suite; diff --git a/modules/img/base/tests/test_function.hh b/modules/img/base/tests/test_function.hh index 4e1d05295235e98e903d9fc13c9fb0722e4e81c0..c0c9f509cc35162dcc5a3e0fb78fd8264a63431f 100644 --- a/modules/img/base/tests/test_function.hh +++ b/modules/img/base/tests/test_function.hh @@ -25,6 +25,7 @@ #ifndef IMG_TEST_FUNCTION_H #define IMG_TEST_FUNCTION_H +#define BOOST_TEST_DYN_LINK #include <boost/test/unit_test.hpp> using boost::unit_test_framework::test_suite; diff --git a/modules/img/base/tests/test_image.cc b/modules/img/base/tests/test_image.cc index 38c4431e529f3f3fa8b37712ef97243f8d28b9f8..dde2a034f900d1f93269f02bdf462324e2867894 100644 --- a/modules/img/base/tests/test_image.cc +++ b/modules/img/base/tests/test_image.cc @@ -312,7 +312,7 @@ void test_ImageOps() ImageHandle h3=h1+h2; for(ExtentIterator it(Extent(Point(-4,-3),Point(4,5))); !it.AtEnd(); ++it) { if(ex1.Contains(it) && ex2.Contains(it)) { - BOOST_REQUIRE(std::fabs(h3.GetReal(it)-(h1.GetReal(it)+h2.GetReal(it)))<1e-10); + BOOST_REQUIRE(check_close(std::fabs(h3.GetReal(it)-(h1.GetReal(it)+h2.GetReal(it))),Real(0.0),1e-6)); } else if (ex1.Contains(it)) { BOOST_REQUIRE(h3.GetReal(it)==h1.GetReal(it)); } else { @@ -324,7 +324,7 @@ void test_ImageOps() h3=h1-h2; for(ExtentIterator it(Extent(Point(-2,-1),Point(1,2))); !it.AtEnd(); ++it) { if(ex1.Contains(it) && ex2.Contains(it)) { - BOOST_REQUIRE(std::fabs(h3.GetReal(it)-(h1.GetReal(it)-h2.GetReal(it)))<1e-10); + BOOST_REQUIRE(check_close(std::fabs(h3.GetReal(it)-(h1.GetReal(it)-h2.GetReal(it))),Real(0.0),1e-6)); } else if (ex1.Contains(it)) { BOOST_REQUIRE(h3.GetReal(it)==h1.GetReal(it)); } else { diff --git a/modules/img/base/tests/test_image.hh b/modules/img/base/tests/test_image.hh index 7120d2338049bc2fde17056142de4f54b578b8a4..a8119a975ff911998f33d295902f4dbec6789656 100644 --- a/modules/img/base/tests/test_image.hh +++ b/modules/img/base/tests/test_image.hh @@ -25,6 +25,7 @@ #ifndef IMG_TEST_IMAGE_H #define IMG_TEST_IMAGE_H +#define BOOST_TEST_DYN_LINK #include <boost/test/unit_test.hpp> using boost::unit_test_framework::test_suite; diff --git a/modules/img/base/tests/test_image_factory.hh b/modules/img/base/tests/test_image_factory.hh index 6912f13698ff1e40e8d59b13828f6754bdbed2ff..aeaffb84e5394fe73700bbe53f4da1e3b97f4ee6 100644 --- a/modules/img/base/tests/test_image_factory.hh +++ b/modules/img/base/tests/test_image_factory.hh @@ -25,6 +25,7 @@ #ifndef IMG_TEST_IMAGE_FACTORY_H #define IMG_TEST_IMAGE_FACTORY_H +#define BOOST_TEST_DYN_LINK #include <boost/test/unit_test.hpp> using boost::unit_test_framework::test_suite; diff --git a/modules/img/base/tests/test_image_impl.hh b/modules/img/base/tests/test_image_impl.hh index 5cbee44f54b4a79912dea0f9e5e1367933c50bf4..10effda5f6eb76fa9c4df3762283159b63633bff 100644 --- a/modules/img/base/tests/test_image_impl.hh +++ b/modules/img/base/tests/test_image_impl.hh @@ -25,6 +25,7 @@ #ifndef IMG_TEST_IMAGE_IMPL_H #define IMG_TEST_IMAGE_IMPL_H +#define BOOST_TEST_DYN_LINK #include <boost/test/unit_test.hpp> using boost::unit_test_framework::test_suite; diff --git a/modules/img/base/tests/test_image_state.hh b/modules/img/base/tests/test_image_state.hh index b288c5a0482283c8d3fb0ec0710a7d82d640224c..13735a9ad26527802eddbd68072447b4362a9f4d 100644 --- a/modules/img/base/tests/test_image_state.hh +++ b/modules/img/base/tests/test_image_state.hh @@ -25,6 +25,7 @@ #ifndef TEST_IMAGE_STATE_H #define TEST_IMAGE_STATE_H +#define BOOST_TEST_DYN_LINK #include <boost/test/unit_test.hpp> using boost::unit_test_framework::test_suite; diff --git a/modules/img/base/tests/test_image_state_visitor.hh b/modules/img/base/tests/test_image_state_visitor.hh index 6cbe26de8d8c8239de6c7314b8165be603c8a1e0..a85f5130ecd164bc60d0008d3e9a923365f25d03 100644 --- a/modules/img/base/tests/test_image_state_visitor.hh +++ b/modules/img/base/tests/test_image_state_visitor.hh @@ -25,6 +25,7 @@ #ifndef IMG_TEST_IMAGE_STATE_VISITOR_H #define IMG_TEST_IMAGE_STATE_VISITOR_H +#define BOOST_TEST_DYN_LINK #include <boost/test/unit_test.hpp> using boost::unit_test_framework::test_suite; diff --git a/modules/img/base/tests/test_index.hh b/modules/img/base/tests/test_index.hh index 5056c4db244ab049ab24716b44c3fa1f8f511c3b..9c21122b2c6d7edf7aa536a2944d63554e66d109 100644 --- a/modules/img/base/tests/test_index.hh +++ b/modules/img/base/tests/test_index.hh @@ -25,6 +25,7 @@ #ifndef IMG_TEST_INDEX_H #define IMG_TEST_INDEX_H +#define BOOST_TEST_DYN_LINK #include <boost/test/unit_test.hpp> using boost::unit_test_framework::test_suite; diff --git a/modules/img/base/tests/test_point.hh b/modules/img/base/tests/test_point.hh index 1c5d20a57c13051b61c071c1ff601eb826cafaea..6b790bc077855517ff84290bc55cf2ed83363641 100644 --- a/modules/img/base/tests/test_point.hh +++ b/modules/img/base/tests/test_point.hh @@ -25,6 +25,7 @@ #ifndef IMG_TEST_POINT_H #define IMG_TEST_POINT_H +#define BOOST_TEST_DYN_LINK #include <boost/test/unit_test.hpp> using boost::unit_test_framework::test_suite; diff --git a/modules/img/base/tests/test_sampling.hh b/modules/img/base/tests/test_sampling.hh index 6854438fc682e33aa5e41c68f0e8674c48a0b18c..cb808f567eb6593203beb1efd8565f601f68e76d 100644 --- a/modules/img/base/tests/test_sampling.hh +++ b/modules/img/base/tests/test_sampling.hh @@ -25,6 +25,7 @@ #ifndef IMG_TEST_SAMPLING_H #define IMG_TEST_SAMPLING_H +#define BOOST_TEST_DYN_LINK #include <boost/test/unit_test.hpp> using boost::unit_test_framework::test_suite; diff --git a/modules/img/base/tests/test_size.hh b/modules/img/base/tests/test_size.hh index 2a35c3e850a796277e5b2a6dbd24c20d04531f33..61b456f29a9f2e654bd68f04942721511d3d6fef 100644 --- a/modules/img/base/tests/test_size.hh +++ b/modules/img/base/tests/test_size.hh @@ -25,6 +25,7 @@ #ifndef IMG_TEST_SIZE_H #define IMG_TEST_SIZE_H +#define BOOST_TEST_DYN_LINK #include <boost/test/unit_test.hpp> using boost::unit_test_framework::test_suite; diff --git a/modules/img/base/tests/test_transform.hh b/modules/img/base/tests/test_transform.hh index cf6b002f7a3d806d4066f8da4d39f19d8206caf7..2569640d50ad21977372ee42bbe4e7d8884542b6 100644 --- a/modules/img/base/tests/test_transform.hh +++ b/modules/img/base/tests/test_transform.hh @@ -25,6 +25,7 @@ #ifndef IMG_TEST_TRANSFORM_H #define IMG_TEST_TRANSFORM_H +#define BOOST_TEST_DYN_LINK #include <boost/test/unit_test.hpp> using boost::unit_test_framework::test_suite; diff --git a/modules/img/base/tests/test_value_holder.hh b/modules/img/base/tests/test_value_holder.hh index 6f2de7bb260a8336120a13bad16af087872b09c8..ecf2d998d692f481ef67fb67c97e0e6993859da5 100644 --- a/modules/img/base/tests/test_value_holder.hh +++ b/modules/img/base/tests/test_value_holder.hh @@ -25,6 +25,7 @@ #ifndef IMG_TEST_VALUE_HOLDER_H #define IMG_TEST_VALUE_HOLDER_H +#define BOOST_TEST_DYN_LINK #include <boost/test/unit_test.hpp> using boost::unit_test_framework::test_suite; diff --git a/modules/index.rst b/modules/index.rst index 52dcde170b022e7824aa2cedd23d3a5c3c65332d..cdb3284d5b4d8ba64311e151052d0200d4a1d66f 100644 --- a/modules/index.rst +++ b/modules/index.rst @@ -2,7 +2,39 @@ OpenStructure documentation ================================================================================ .. toctree:: + :maxdepth: 2 + +Introduction +-------------------------------------------------------------------------------- - geom/doc/geom - conop/doc/conop - mol/base/doc/mol \ No newline at end of file +.. toctree:: + :maxdepth: 2 + + intro + install + +Modules +-------------------------------------------------------------------------------- + +.. toctree:: + :maxdepth: 2 + + base/generic + img/base/img + img/alg/alg + geom/geom + conop/conop + mol/base/mol + seq/base/seq + base/base + io/io + +Extending OpenStructure +-------------------------------------------------------------------------------- + +.. toctree:: + :maxdepth: 2 + + newmodule + external + \ No newline at end of file diff --git a/modules/io/doc/formats.rst b/modules/io/doc/formats.rst new file mode 100644 index 0000000000000000000000000000000000000000..ceef7e5f25111f28e50c66a966fdacf6d621bc61 --- /dev/null +++ b/modules/io/doc/formats.rst @@ -0,0 +1,81 @@ +Supported File Formats +================================================================================ + +Structure File Formats +-------------------------------------------------------------------------------- + +The following file formats are supported by :func:`~ost.io.LoadEntity`. + + + +PDB - Brookhaven PDB File +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Fine grained control over PDB file import is available via the +:func:`~ost.io.LoadPDB` function. The PDB importer support loading gzipped PDB +files. gzipped PDB files are detected by the .gz file extension. + +*Recognized File Extensions* + ent, pdb, ent.gz, pdb.gz + +*Format Name* + pdb + +PQR +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +*Recognized File Extensions* + pqr + +*Format Name* + pqr + +CRD - CARD format file used by CHARMM +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +*Recognized File Extensions* + crd + +SDF +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +*Recognized File Extensions* + sdf + +Sequence File Formats +-------------------------------------------------------------------------------- + +FASTA +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +*Recognized File Extensions* + fasta, fna, fas, fa, fsa + +*Format Name* + fasta + +ClustalW +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +*Recognized File Extensions* + aln + +*Format Name* + clustal + +Promod +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +*Recognized File Extensions* + ali + +*Format Name* + promod + +PIR +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +*Recognized File Extensions* + pir + +*Format Name* + pir \ No newline at end of file diff --git a/modules/io/doc/io.rst b/modules/io/doc/io.rst new file mode 100644 index 0000000000000000000000000000000000000000..21c38bc4f93f2ce10b4357004c9c688f310a178a --- /dev/null +++ b/modules/io/doc/io.rst @@ -0,0 +1,103 @@ +:mod:`~ost.io` - Input and Output of Sequences, Structures and Maps +================================================================================ + +.. module:: ost.io + :synopsis: Input and output of sequences, structures and density maps + +The io module deals with input and output of :class:`entities +<ost.mol.EntityHandle>`, :class:`alignments <ost.seq.AlignmentHandle>`, and +:class:`images <ost.img.ImageHandle>`. Importers for common file formats such +as PDB, SDF, FASTA, CLUSTAL W, DX and CHARMM trajectory files are available. + +Molecular Structures +-------------------------------------------------------------------------------- + +Loading Molecular Structures +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The :mod:`~ost.io` modules offers several ways to load molecular structures +depending on your requirements. The most general way is offered by +:func:`~ost.io.LoadEntity`, which will automatically detect the file format based +on the file extension. + +.. function:: LoadEntity(filename, format='auto') + + Load entity from disk. If format is set to 'auto', the function guesses the + filetype based on the extension of the file. Files ending in '.pdb', '.ent', + '.ent.gz', '.pdb.gz' will automatically be loaded as PDB files, for example. + For files without or exotic extensions, the format can be set explicitly as + the second parameter. + + .. code-block:: python + + # recognizes SDF file by file extension + ent=io.LoadEntity('file.sdf') + + # In this case, there is no file extensions, so you have to say it's a + # SDF file explicitly + ent=io.LoadEntity('file', 'sdf') + + For a list of file formats supported by :func:`LoadEntity`, see :doc:`formats`. + + :raises: :exc:`~ost.io.IOUnknownFormatException` if the format string supplied + is not recognized or the file format can not be detected based on the + file extension + + :exc:`~ost.io.IOException` if the import fails due to an erroneous or + inexistent file + +Some of the formats have a dedicated function that allows you to tweak many +parameters that affect the import. PDB files can be loaded with +:func:`~ost.io.LoadPDB`. It offers a tighter control over the exact loading +behaviour. + +.. autofunction:: ost.io.LoadPDB + + +Saving Molecular Structures +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Saving a complete entity or a view is a matter of calling +:func:`~ost.io.SaveEntity`. + +.. code-block:: python + + ent=io.LoadEntity('protein.pdb') + # save full entity + io.SaveEntity(ent, 'full.pdb') + # only save C-alpha atoms + io.SaveEntity(ent.Select('aname=CA and peptide=true'), 'calpha.pdb') + +:func:`~ost.io.SavePDB` provides a simple way to save several entities into one +file: + + +.. code-block:: python + + ent=io.LoadEntity('protein.pdb') + # Save complete entity + io.SavePDB(ent, 'full.pdb') + # Save chain A and chain B separately + io.SavePDB([ent.Select('cname=A'), ent.Select('cname=B')], 'split.pdb') + + +.. function:: SaveEntity(ent, filename, format='auto') + + Save entity to disk. If format is set to 'auto', the function guesses the + filetype based on the file extension, otherwise the supplied format is checked + against the available export plugins. + + :param ent: The entity to be saved + :type ent: :class:`~ost.mol.EntityHandle` or :class:`~ost.mol.EntityView` + :param filename: The filename + :type filename: string + :param format: Name of the format + :type format: string + + :raises: :exc:`~ost.io.IOUnknownFormatException` if the format string supplied + is not recognized or the file format can not be detected based on the + file extension + +.. autofunction:: ost.io.SavePDB + + \ No newline at end of file diff --git a/modules/io/pymod/__init__.py b/modules/io/pymod/__init__.py index 344f971292b41d79cddbb61925c71d5296d0d474..095cacb8953c011a2e37f4946b6b21eee00a5286 100644 --- a/modules/io/pymod/__init__.py +++ b/modules/io/pymod/__init__.py @@ -17,29 +17,35 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #------------------------------------------------------------------------------ from _io import * -from ost import mol,conop +from ost import mol, conop def LoadPDB(filename, restrict_chains="", no_hetatms=False, fault_tolerant=False, load_multi=False, join_spread_atom_records=False, calpha_only=False): """ - Load PDB file from disk. + Load PDB file from disk and returns one or more entities. Several options + allow to customize the exact behaviour of the PDB import. - If restrict_chains is not an empty string, only chains listed in the - string will be imported. + :param restrict_chains: If not an empty string, only chains listed in the + string will be imported. - If fault_tolerant is set to true, the import will succeed, even if the - PDB contains faulty records. The faulty records will be ignored in that - case. + :param fault_tolerant: If True, the import will succeed, even if the + PDB contains faulty records. The faulty records will be ignored and import + continues as if the records haven't been present. - If not_hetatms is set to True, HETATM records will be ignored + :param no_hetatms: If set to True, HETATM records will be ignored - If load_multi is set to true, a list of entities will be returned instead - of only the first. + :param load_multi: If set to True, a list of entities will be returned instead + of only the first. This is useful when dealing with multi-PDB files. - If join_spread_atom_records is set to true, atom records belonging to the - same residue are joined, even if they do not appear sequentially in the PDB - file. + :param join_spread_atom_records: If set to true, atom records belonging to the + same residue are joined, even if they do not appear sequentially in the PDB + file. + :rtype: :class:`~ost.mol.EntityHandle` or a list thereof if `load_multi` is + True. + + :raises: :exc:`~ost.io.IOException` if the import fails due to an erroneous or + inexistent file """ conop_inst=conop.Conopology.Instance() builder=conop_inst.GetBuilder("DEFAULT") @@ -78,7 +84,13 @@ def LoadPDB(filename, restrict_chains="", no_hetatms=False, def SavePDB(models, filename): """ - Save entity or list of entities to disk + Save entity or list of entities to disk. If a list of entities is supplied the + PDB file will be saved as a multi PDB file. Each of the entities is wrapped + into a MODEL/ENDMDL pair. + + :param models: The entity or list of entities (handles or views) to be saved + :param filename: The filename + :type filename: string """ if not getattr(models, '__len__', None): models=[models] diff --git a/modules/io/src/CMakeLists.txt b/modules/io/src/CMakeLists.txt index e77cfda20a98d8b856113f12c0b50deb470a2e92..f61c471d31a52f363fb17d43917719b927ebe06c 100644 --- a/modules/io/src/CMakeLists.txt +++ b/modules/io/src/CMakeLists.txt @@ -13,6 +13,7 @@ io_utils.hh io_exception.hh convert.hh converting_streams.hh +formatted_line.hh ) set(OST_IO_SOURCES diff --git a/modules/io/src/formatted_line.hh b/modules/io/src/formatted_line.hh new file mode 100644 index 0000000000000000000000000000000000000000..444a4e4aaf75c14452b868d4b5a857cc28fa956c --- /dev/null +++ b/modules/io/src/formatted_line.hh @@ -0,0 +1,239 @@ +#ifndef OST_IO_FORMATTED_LINE_HH +#define OST_IO_FORMATTED_LINE_HH + +#ifdef _MSC_VER +#define snprintf _snprintf +#endif + +#include <cstdio> + +#include <ost/string_ref.hh> + +/* + Author: Marco Biasini + */ + +namespace ost { namespace io { + +namespace fmt { + +struct LPadded : public StringRef { + LPadded(const char* s, size_t l): + StringRef(s, l) + { } + + explicit LPadded(const String& s): StringRef(s.data(), s.size()) + { } + + explicit LPadded(const char* s): StringRef(s, strlen(s)) + { } +}; + +struct RPadded : public StringRef { + RPadded(const char* s, size_t l): + StringRef(s, l) + { } + + explicit RPadded(const String& s): StringRef(s.data(), s.size()) + { } + + explicit RPadded(const char* s): StringRef(s, strlen(s)) + { } +}; + + +struct LPaddedInt { + LPaddedInt(int val) { + size_t curr=0; + bool minus=val<0; + val=std::abs(val); + if (minus) { + data[curr]='-'; + ++curr; + } + do { + int m=val%10; + data[curr]='0'+m; + ++curr; + val/=10; + } while(val); + // swap + for (size_t i=0, e=(curr-int(minus))/2; i<e; ++i) { + std::swap(data[int(minus)+i], data[curr-i-1]); + } + data[curr]='\0'; + len=curr; + } + char data[20]; + size_t len; +}; + +// BIG FAT WARNING: Before using this class to output floats with lots of +// digits, make sure you indeed get the result you want. The function has +// not been tested enough for numerical stability. +struct LPaddedFloat { + LPaddedFloat(Real val, int prec) + { + switch(prec){ + case 0: + len = snprintf(data, sizeof(data), "%.0f", val); + break; + case 1: + len = snprintf(data, sizeof(data), "%.1f", val); + break; + case 2: + len = snprintf(data, sizeof(data), "%.2f", val); + break; + case 3: + len = snprintf(data, sizeof(data), "%.3f", val); + break; + default: + Real rounded_val=round(val*pow(Real(10), prec))*pow(Real(0.1), prec); + size_t curr=0; + bool minus=rounded_val<0; + rounded_val=std::abs(rounded_val); + int int_val=int(rounded_val); + if (minus) { + data[curr]='-'; + ++curr; + } + do { + int m=int_val%10; + data[curr]='0'+m; + ++curr; + int_val/=10; + } while(int_val); + // swap + for (size_t i=0, e=(curr-int(minus))/2; i<e; ++i) { + std::swap(data[int(minus)+i], data[curr-i-1]); + } + data[curr]='\0'; + len=curr; + if (prec==0) { + return; + } + data[curr]='.'; + curr++; + rounded_val-=int(rounded_val); + while(prec>0) { + rounded_val*=10; + int m=int(rounded_val); + rounded_val-=int(rounded_val); + data[curr]='0'+m; + curr++; + --prec; + } + data[curr]='\0'; + len=curr; + } + } + char data[20]; + size_t len; +}; + + + +} + +class LineSlice { +public: + LineSlice(char* data, size_t l): data_(data), len_(l) + { + } + + LineSlice& operator=(const StringRef& str) + { + assert(str.length()==len_); + memcpy(data_, str.data(), str.size()); + return *this; + } + + LineSlice& operator=(const fmt::LPadded& str) + { + assert(str.size()<=len_); + memcpy(data_+len_-str.size(), str.data(), str.size()); + return *this; + } + + LineSlice& operator=(const fmt::RPadded& str) + { + assert(str.size()<=len_); + memcpy(data_, str.data(), str.size()); + return *this; + } + + LineSlice& operator=(const fmt::LPaddedInt& i) + { + assert(i.len<=len_); + memcpy(data_+len_-i.len, i.data, i.len); + return *this; + } + + LineSlice& operator=(const fmt::LPaddedFloat& f) + { + assert(f.len<=len_); + memcpy(data_+len_-f.len, f.data, f.len); + return *this; + } + void Clear() + { + memset(data_, ' ', len_); + } +private: + char* data_; + size_t len_; +}; + +class FormattedLine { +public: + FormattedLine(size_t width): + data_(new char[width]), len_(width) + { + this->Clear(); + } + + void Clear() + { + memset(data_, ' ', len_); + } + ~FormattedLine() { delete[] data_; } + + LineSlice operator()(int start, int len) + { + assert(start>=0 && start+len<=static_cast<int>(len_)); + return LineSlice(data_+start, len); + } + + const char* Data() const { return data_; } + + size_t GetWidth() const { return len_; } + + char operator[](size_t index) const + { + assert(index<len_); + return data_[index]; + } + + char& operator[](size_t index) + { + assert(index<len_); + return data_[index]; + } +private: + FormattedLine& operator=(const FormattedLine& rhs); + FormattedLine(const FormattedLine& rhs); + char* data_; + size_t len_; +}; + +inline std::ostream& operator<<(std::ostream& stream, const FormattedLine& line) +{ + stream.write(line.Data(), line.GetWidth()); + stream << std::endl; + return stream; +} + + +}} + +#endif diff --git a/modules/io/src/mol/CMakeLists.txt b/modules/io/src/mol/CMakeLists.txt index 5cdf0462bb889d48a63a4d64092b0297d5270102..860b4df0d09e6525952e9728389b436f1fe8db5d 100644 --- a/modules/io/src/mol/CMakeLists.txt +++ b/modules/io/src/mol/CMakeLists.txt @@ -6,6 +6,8 @@ entity_io_pdb_handler.cc pdb_io.cc pdb_writer.cc entity_io_sdf_handler.cc +sdf_reader.cc +sdf_writer.cc save_entity.cc load_entity.cc surface_io_msms_handler.cc @@ -26,6 +28,8 @@ pdb_reader.hh entity_io_pdb_handler.hh pdb_writer.hh entity_io_sdf_handler.hh +sdf_reader.hh +sdf_writer.hh save_entity.hh load_entity.hh surface_io_handler.hh diff --git a/modules/io/src/mol/entity_io_mae_handler.cc b/modules/io/src/mol/entity_io_mae_handler.cc index 03700f62a350cf827a1edce0a56ec54707ddbe6b..d002a712035e21f4ab96bc47de7c2785cd6f5999 100644 --- a/modules/io/src/mol/entity_io_mae_handler.cc +++ b/modules/io/src/mol/entity_io_mae_handler.cc @@ -133,7 +133,7 @@ void MAEReader::Import(mol::EntityHandle& ent) } else { // parsing atom line std::vector<std::string> tokens=tokenize(line); - for(int i=0;i<tokens.size();++i) { + for(size_t i=0;i<tokens.size();++i) { LOG_DUMP( "[" << tokens[i] << "] "); } LOGN_DUMP(""); diff --git a/modules/io/src/mol/entity_io_sdf_handler.cc b/modules/io/src/mol/entity_io_sdf_handler.cc index f9c49479ffbebaf52a4d03a18cafe4cb69a20c67..72ec53cbc9f2a3026881809c3574a891551d8fc5 100644 --- a/modules/io/src/mol/entity_io_sdf_handler.cc +++ b/modules/io/src/mol/entity_io_sdf_handler.cc @@ -16,392 +16,50 @@ // along with this library; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA //------------------------------------------------------------------------------ -#include <iostream> -#include <sstream> -#include <iomanip> +/* + Author: Tobias Schmidt + */ -#include <boost/filesystem/fstream.hpp> -#include <boost/filesystem/convenience.hpp> -#include <boost/algorithm/string.hpp> -#include <boost/lexical_cast.hpp> -#include <boost/format.hpp> #include <ost/log.hh> -#include <ost/conop/conop.hh> -#include <ost/io/io_exception.hh> +#include <ost/io/sdf_writer.hh> +#include <ost/io/sdf_reader.hh> + #include "entity_io_sdf_handler.hh" namespace ost { namespace io { -using boost::format; bool EntityIOSDFHandler::RequiresBuilder() const { return false; } -// import data from provided stream -void EntityIOSDFHandler::Import(mol::EntityHandle& ent, std::istream& instream) +void EntityIOSDFHandler::Import(mol::EntityHandle& ent, + std::istream& instream) { - String line; - mol::XCSEditor editor=ent.RequestXCSEditor(mol::BUFFERED_EDIT); - while (std::getline(instream,line)) { - ++line_num; - - if (line_num<=4) { - ParseAndAddHeader(line, line_num, ent, editor); - } else if (line_num<=atom_count_+4) { - ParseAndAddAtom(line, line_num, ent, true, editor); - } else if (line_num<=bond_count_+atom_count_+4) { - ParseAndAddBond(line, line_num, ent, editor); - } else if (boost::iequals(line.substr(0,2), "> ")) { - // parse data items - int data_header_start = line.find('<'); - String data_header = line.substr(data_header_start+1,line.rfind('>')-data_header_start-1); - if(data_header.empty()) { - String msg="Bad data line %d: Could not find data header"; - throw IOException(str(format(msg) % line_num)); - } - String data_value=""; - while(std::getline(instream,line) && !boost::iequals(line, "")) { - data_value.append(line); - } - curr_chain_.SetStringProp(data_header, data_value); - } else if (boost::iequals(line, "$$$$")) { - LOGN_MESSAGE("MOLECULE " << curr_chain_.GetName() << " (" << chain_count_ << ") added.") - NextMolecule(); - } - } - - LOGN_MESSAGE("imported " << chain_count_ << " chains, " << residue_count_ - << " residues, " << atom_count_ << " atoms"); + SDFReader reader(instream); + reader.Import(ent); } - - void EntityIOSDFHandler::Import(mol::EntityHandle& ent, const boost::filesystem::path& loc) { - ClearState(); - boost::filesystem::ifstream instream(loc); - if(!instream) throw IOException("could not open "+loc.string()); - this->Import(ent, instream); -} - -void EntityIOSDFHandler::ClearState() -{ - curr_chain_=mol::ChainHandle(); - curr_residue_=mol::ResidueHandle(); - chain_count_=0; - residue_count_=0; - atom_count_=0; - bond_count_=0; - line_num=0; -} - -void EntityIOSDFHandler::NextMolecule() -{ - residue_count_=0; - atom_count_=0; - bond_count_=0; - line_num=0; -} - -void EntityIOSDFHandler::ParseAndAddHeader(const String& line, int line_num, - mol::EntityHandle& ent, mol::XCSEditor& editor) -{ - LOGN_TRACE( "line: [" << line << "]" ); - format chain_fmter("%05i_%s"); - switch(line_num) - { - case 1: // title line - { - ++chain_count_; - String s_title=line; - String s_chain; - chain_fmter % chain_count_ % boost::trim_copy(s_title); - s_chain=chain_fmter.str(); - if(s_chain.empty()) { - String msg="Bad molecule name line %d: Line is empty"; - throw IOException(str(format(msg) % line_num)); - } - curr_chain_=editor.InsertChain(s_chain); - LOGN_DUMP("new chain " << s_chain); - - mol::ResidueKey rkey=boost::trim_copy(s_title); - mol::ResNum rnum(++residue_count_); - curr_residue_=editor.AppendResidue(curr_chain_, rkey, rnum); - LOGN_DUMP("new residue " << rkey << "(" << rnum << ")"); - break; - } - case 2: // user information line - break; - case 3: // comments line - break; - case 4: // counts line - { - String s_anum=line.substr(0,3); - try { - atom_count_=boost::lexical_cast<int>(boost::trim_copy(s_anum)); - } catch(boost::bad_lexical_cast&) { - String msg="Bad counts line %d: Can't convert number of atoms" - " '%s' to integral constant."; - throw IOException(str(format(msg) % line_num % s_anum)); - } - String s_bnum=line.substr(3,3); - try { - bond_count_=boost::lexical_cast<int>(boost::trim_copy(s_bnum)); - } catch(boost::bad_lexical_cast&) { - String msg="Bad counts line %d: Can't convert number of bonds" - " '%s' to integral constant."; - throw IOException(str(format(msg) % line_num % s_bnum)); - } - break; - } - } -} - -void EntityIOSDFHandler::ParseAndAddAtom(const String& line, int line_num, - mol::EntityHandle& ent, bool hetatm, - mol::XCSEditor& editor) -{ - - LOGN_TRACE( "line: [" << line << "]" ); - - if(line.length()<48 || line.length()>69) { - String msg="Bad atom line %d: Not correct number of characters on the" - " line: %i (should be between 48 and 69)"; - throw IOException(str(format(msg) % line_num % line.length())); - } - int anum = line_num-4; // start at 1 on fifth line since first four lines are header - String s_posx=line.substr(0,10); - String s_posy=line.substr(10,10); - String s_posz=line.substr(20,10); - String s_ele=line.substr(31,3); - String s_charge=line.substr(36,3); - - geom::Vec3 apos; - try { - apos=geom::Vec3(boost::lexical_cast<Real>(boost::trim_copy(s_posx)), - boost::lexical_cast<Real>(boost::trim_copy(s_posy)), - boost::lexical_cast<Real>(boost::trim_copy(s_posz))); - } catch(boost::bad_lexical_cast&) { - String msg="Bad atom line %d: Can't convert coordinates to " - "floating point numbers"; - throw IOException(str(format(msg) % line_num)); - } - - String ele=boost::trim_copy(s_ele); - String aname=boost::lexical_cast<String>(anum); - - mol::AtomProp aprop; - aprop.element=ele; - aprop.radius=conop::Conopology::Instance().GetDefaultAtomRadius(ele); - aprop.mass=conop::Conopology::Instance().GetDefaultAtomMass(ele); - aprop.is_hetatm=hetatm; - - try { - aprop.charge=boost::lexical_cast<Real>(boost::trim_copy(s_charge)); - if(aprop.charge != 0) { - aprop.charge=4-aprop.charge; - } //4-sdf_charge=real_charge if not 0 - } catch(boost::bad_lexical_cast&) { - String msg="Bad atom line %d: Can't convert charge" - " '%s' to integral constant."; - throw IOException(str(format(msg) % line_num % s_charge)); - } - - LOGN_DUMP("adding atom " << aname << " (" << s_ele << ") @" << apos); - - editor.InsertAtom(curr_residue_, aname,apos,aprop); -} - - -void EntityIOSDFHandler::ParseAndAddBond(const String& line, int line_num, - mol::EntityHandle& ent, mol::XCSEditor& editor) -{ - - LOGN_TRACE( "line: [" << line << "]" ); - - if(line.length()<18 || line.length()>21) { - String msg="Bad bond line %d: Not correct number of characters on the" - " line: %i (should be between 18 and 21)"; - throw IOException(str(format(msg) % line_num % line.length())); - } - - String s_first_name=line.substr(0,3); - String s_second_name=line.substr(3,3); - String s_type=line.substr(6,3); - String first_name, second_name; - unsigned char type; - mol::BondHandle bond; - - first_name=boost::trim_copy(s_first_name); - second_name=boost::trim_copy(s_second_name); - - try { - type=boost::lexical_cast<int>(boost::trim_copy(s_type)); - } catch(boost::bad_lexical_cast&) { - String msg="Bad bond line %d: Can't convert bond type number" - " '%s' to integral constant."; - throw IOException(str(format(msg) % line_num % s_type)); - } - - mol::AtomHandle first,second; - - first = ent.FindAtom(curr_chain_.GetName(), mol::ResNum(residue_count_), first_name); - second = ent.FindAtom(curr_chain_.GetName(), mol::ResNum(residue_count_), second_name); - - if(first.IsValid() && second.IsValid()) { - bond = editor.Connect(first, second); - bond.SetBondOrder(type); - } else { - String msg="Bad bond line %d: Can't find the atom names '%s', '%s'" - " in entity."; - throw IOException(str(format(msg) % line_num % first % second)); - } - - LOGN_DUMP("adding bond " << s_first_name << " " << s_second_name << " (" << s_type << ") "); -} - -namespace { - - using boost::format; - - class SDFAtomWriter : public mol::EntityVisitor { - public: - SDFAtomWriter(std::ostream& ostream, std::map<long, int>& atom_indices) - : ostr_(ostream), atom_indices_(atom_indices), counter_(0) { - atom_indices_.clear(); - } - private: - public: - virtual bool VisitAtom(const mol::AtomHandle& atom) { - atom_indices_[atom.GetHashCode()] = ++counter_; - ostr_ << format("%10.4f") % atom.GetPos()[0] - << format("%10.4f") % atom.GetPos()[1] - << format("%10.4f ") % atom.GetPos()[2] - << format("%-3s") % atom.GetElement() - << " 0 0 0 0 0 0" - << std::endl; - return true; - } - private: - std::ostream& ostr_; - std::map<long, int>& atom_indices_; - int counter_; - }; - - class SDFBondWriter : public mol::EntityVisitor { - public: - SDFBondWriter(std::ostream& ostream, std::map<long, int>& atom_indices) - : ostr_(ostream), atom_indices_(atom_indices), counter_(0) { - } - private: - public: - virtual bool VisitAtom(const mol::AtomHandle& atom) { - counter_++; - mol::AtomHandleList atoms = atom.GetBondPartners(); - mol::AtomHandleList::iterator atom_iter = atoms.begin(); - for(; atom_iter != atoms.end(); ++atom_iter) { - int atom_index = atom_indices_.find((*atom_iter).GetHashCode())->second; - if(atom_index > counter_) { - int type = 1; - mol::BondHandle bond = atom.FindBondToAtom(*atom_iter); - if(bond.IsValid()) type = bond.GetBondOrder(); - ostr_ << format("%3i") % counter_ - << format("%3i") % atom_index - << format("%3i") % type - << " 0 0 0" - << std::endl; - } - } - return true; - } - - private: - std::ostream& ostr_; - std::map<long, int>& atom_indices_; - int counter_; - }; - - class SDFWriter : public mol::EntityVisitor { - public: - SDFWriter(std::ostream& ostream) - : ostr_(ostream), counter_(0) { - } - private: - public: - virtual bool VisitChain(const mol::ChainHandle& chain) { - // print end of molecule line - if(counter_ != 0) { - ostr_ << "$$$$" << std::endl; - counter_ = 0; - atom_indices_.clear(); - } - // print header lines - ostr_ << chain.GetName() << std::endl; - ostr_ << std::endl; - ostr_ << std::endl; - - // print counts line - ostr_ << format("%3d") % chain.GetAtomCount() - << format("%3d") % chain.GetBondCount() - << " 0 0 0 0 0 0 0 0999 V2000" - << std::endl; - - // write atom block - SDFAtomWriter atom_writer(ostr_, atom_indices_); - mol::ChainHandle non_const_chain = chain; - non_const_chain.Apply(atom_writer); - - // write bond block - SDFBondWriter bond_writer(ostr_, atom_indices_); - non_const_chain.Apply(bond_writer); - - // write property block - //TODO: wirte property block - ostr_ << "M END" << std::endl; - - // write data block - std::map<String,GenericPropValue> prop_map = non_const_chain.GetPropMap(); - std::map<String,GenericPropValue>::iterator iter; - for(iter = prop_map.begin(); iter != prop_map.end(); ++iter) { - ostr_ << "> <" << (*iter).first << ">" << std::endl; - ostr_ << (*iter).second << std::endl; - ostr_ << std::endl; - } - - // write molecule endline - ostr_ << "$$$$" << std::endl; - - return true; - } - - - - private: - std::ostream& ostr_; - int counter_; - std::map<long,int> atom_indices_; - }; - + SDFReader reader(loc); + reader.Import(ent); } void EntityIOSDFHandler::Export(const mol::EntityView& ent, const boost::filesystem::path& loc) const { - boost::filesystem::ofstream outfile(loc); - if(!outfile) throw IOException("could not open "+loc.string()+" for writing"); - this->Export(ent, outfile); + SDFWriter writer(loc); + writer.Write(ent); } -// export data from entity view to provided stream void EntityIOSDFHandler::Export(const mol::EntityView& ent, std::ostream& outstream) const { - SDFWriter writer(outstream); - mol::EntityView non_const_view = ent; - non_const_view.Apply(writer); + SDFWriter writer(outstream); + writer.Write(ent); } namespace { @@ -436,16 +94,12 @@ bool EntityIOSDFHandler::ProvidesExport(const boost::filesystem::path& loc, return sdf_handler_is_responsible_for(loc, type); } - - mol::EntityHandle LoadSDF(const String& file_name) { mol::EntityHandle ent_handle=mol::CreateEntity(); EntityIOSDFHandler ent_io; ent_io.Import(ent_handle,file_name); - LOG_DUMP("running conopology" << std::endl); - return ent_handle; } diff --git a/modules/io/src/mol/entity_io_sdf_handler.hh b/modules/io/src/mol/entity_io_sdf_handler.hh index 1baa629d4470fe979e7119b749fd391e2389d582..cebf2fa5e6297dc10ddf1e42e50dcc564c953b4d 100644 --- a/modules/io/src/mol/entity_io_sdf_handler.hh +++ b/modules/io/src/mol/entity_io_sdf_handler.hh @@ -20,7 +20,6 @@ #define OST_IO_ENTITY_IO_PLUGIN_SDF_H #include <ost/io/mol/entity_io_handler.hh> -#include <ost//mol/xcs_editor.hh> namespace ost { namespace io { @@ -45,29 +44,6 @@ public: static String GetFormatName() { return String("Sdf"); } static String GetFormatDescription() { return String("Structure-data format from Molecular Design Limited"); } - -private: - void ClearState(); - - void NextMolecule(); - - void ParseAndAddHeader(const String& line, int line_num, mol::EntityHandle& ent, - mol::XCSEditor& editor); - - void ParseAndAddAtom(const String& line, int line_num, mol::EntityHandle& ent, - bool hetatm, mol::XCSEditor& editor); - - void ParseAndAddBond(const String& line, int line_num, mol::EntityHandle& ent, - mol::XCSEditor& editor); - - mol::ChainHandle curr_chain_; - mol::ResidueHandle curr_residue_; - int chain_count_; - int residue_count_; - int atom_count_; - int bond_count_; - int line_num; - }; typedef EntityIOHandlerFactory<EntityIOSDFHandler> EntityIOSDFHandlerFactory; diff --git a/modules/io/src/mol/pdb_reader.cc b/modules/io/src/mol/pdb_reader.cc index f26e77672d2ff4aa62c49f8ead2c7d98544423bc..21db6adf023afa1fb733103179b66b4e57188131 100644 --- a/modules/io/src/mol/pdb_reader.cc +++ b/modules/io/src/mol/pdb_reader.cc @@ -404,8 +404,8 @@ void PDBReader::ParseAndAddAtom(const StringRef& line, int line_num, } // b-factors and occ are replaced by radius and charge if PQR file format if(is_pqr_) { - occ=std::make_pair(true, 1.0); - temp=std::make_pair(true, 0.0); + occ=std::make_pair(true, Real(1.0)); + temp=std::make_pair(true, Real(0.0)); if (line.length()>=60) { charge=line.substr(54,6).ltrim().to_float(); } diff --git a/modules/io/src/mol/pdb_writer.cc b/modules/io/src/mol/pdb_writer.cc index 775bec870c7f4fc2ef02e4a8087472060803a37c..7b89e1f09cbfea8857fb9057285fcfd16f515c7f 100644 --- a/modules/io/src/mol/pdb_writer.cc +++ b/modules/io/src/mol/pdb_writer.cc @@ -19,9 +19,12 @@ /* Author: Marco Biasini */ +#include <locale> #include <boost/format.hpp> #include <string.h> + #include <ost/io/io_exception.hh> + #include "pdb_writer.hh" using boost::format; @@ -31,63 +34,119 @@ namespace ost { namespace io { namespace { -void write_atom(std::ostream& ostr, const mol::AtomHandle& atom, int atomnum, +// determine whether the element name has to be shifted to to the left by one +// column. +bool shift_left(const String& atom_name, bool is_hetatm, + const String& element, float mass) +{ + if (is_hetatm==false) { + return false; + } + + if (isdigit(atom_name[0]) || atom_name=="UNK" || + atom_name.length()==4) { + return true; + } + if (mass>34) { + if (element=="W" || element=="V") { + return false; + } + return true; + } + return (element=="K" || element=="CA" || element=="NA" || + element=="MG" || element=="LI"); +} + +void write_atom(std::ostream& ostr, FormattedLine& line, + const mol::AtomHandle& atom, int atomnum, bool is_pqr) { mol::ResidueHandle res=atom.GetResidue(); char ins_code=res.GetNumber().GetInsCode(); - String record_name=atom.GetAtomProps().is_hetatm ? "HETATM" : "ATOM "; - String aname_str=atom.GetName(); - if(aname_str.length()<4) { - aname_str=" "+aname_str; - } + StringRef record_name(atom.IsHetAtom() ? "HETATM" : "ATOM ", 6); std::vector<String> names=atom.GetAltGroupNames(); + + geom::Vec3 p=atom.GetPos(); + line( 0, 6)=record_name; + line( 6, 5)=fmt::LPaddedInt(atomnum); + String atom_name=atom.GetName(); + if (atom_name.size()>4) { + throw IOException("Atom name '"+atom.GetQualifiedName()+ + "' is too long for PDB output. At most 4 character " + "are allowed"); + } + if (shift_left(atom_name, atom.IsHetAtom(), atom.GetElement(), + atom.GetMass())) { + line(12, 4)=fmt::RPadded(atom_name); + } else { + line(13, 3)=fmt::RPadded(atom_name); + } + if (res.GetKey().size()>3) { + throw IOException("Residue name '"+res.GetQualifiedName()+ + "' is too long for PDB output. At most 3 characters are " + "allowed"); + } + line(17, 3)=fmt::LPadded(res.GetKey()); + + String chain_name=res.GetChain().GetName(); + if (chain_name.size()>0) { + if (chain_name.size()==1) { + line[21]=chain_name[0]; + } else { + throw IOException("PDB format only support single-letter chain names"); + } + } + line(22, 4)=fmt::LPaddedInt(res.GetNumber().GetNum()); + if (ins_code!=0) { + line[26]=ins_code; + } + + // deal with alternative atom locations if (names.empty()) { - geom::Vec3 p=atom.GetPos(); - String ins_str=(ins_code==0 ? " " : String(1, ins_code)); - ostr << record_name << format("%5d") % atomnum - << format(" %-4s") % aname_str - << " " - << format("%.3s") % res.GetKey() - << format(" %.1s") % res.GetChain().GetName() - << format("%4d%s") % res.GetNumber().GetNum() % ins_str - << " " - << format("%8.3f%8.3f%8.3f") % p[0] % p[1] % p[2]; - if(is_pqr) { - ostr << format("%6.2f") % atom.GetAtomProps().charge - << format("%6.2f") % atom.GetAtomProps().radius; + line(30, 8)=fmt::LPaddedFloat(p[0], 3); + line(38, 8)=fmt::LPaddedFloat(p[1], 3); + line(46, 8)=fmt::LPaddedFloat(p[2], 3); + + if (is_pqr) { + line(54, 6)=fmt::LPaddedFloat(atom.GetCharge(), 2); + line(60, 6)=fmt::LPaddedFloat(atom.GetRadius(), 2); } else { - ostr << format("%6.2f") % atom.GetAtomProps().occupancy - << format("%6.2f") % atom.GetAtomProps().b_factor; + line(54, 6)=fmt::LPaddedFloat(atom.GetOccupancy(), 2); + line(60, 6)=fmt::LPaddedFloat(atom.GetBFactor(), 2); } - ostr << format("%10s%2s") % "" % atom.GetAtomProps().element - << std::endl - ; + + line(76, 2)=fmt::LPadded(atom.GetElement()); + ostr << line; } else { - for (std::vector<String>::const_iterator i=names.begin(), - e=names.end(); i!=e; ++i) { - geom::Vec3 p=atom.GetAltPos(*i); - String ins_str=(ins_code==0 ? " " : String(1, ins_code)); - ostr << record_name << format("%5d") % atomnum - << format(" %-4s") % aname_str - << *i - << format("%.3s") % res.GetKey() - << format(" %.1s") % res.GetChain().GetName() - << format("%4d%s") % res.GetNumber().GetNum() % ins_str - << " " - << format("%8.3f%8.3f%8.3f") % p[0] % p[1] % p[2]; - if(is_pqr) { - ostr << format("%6.2f") % atom.GetAtomProps().charge - << format("%6.2f") % atom.GetAtomProps().radius; - } else { - ostr << format("%6.2f") % atom.GetAtomProps().occupancy - << format("%6.2f") % atom.GetAtomProps().b_factor; - } - ostr << format("%10s%2s") % "" % atom.GetAtomProps().element - << std::endl - ; + for (std::vector<String>::const_iterator + i=names.begin(), e=names.end(); i!=e; ++i) { + p=atom.GetAltPos(*i); + line(30, 50).Clear(); + + if (i->size()>1) { + throw IOException("Alternative atom indicator '"+atom.GetQualifiedName()+ + "("+*i+")' too long for PDB output. At most 1 " + "character is allowed"); + } + line[16]=(*i)[0]; + line(30, 8)=fmt::LPaddedFloat(p[0], 3); + line(38, 8)=fmt::LPaddedFloat(p[1], 3); + line(46, 8)=fmt::LPaddedFloat(p[2], 3); + + if (is_pqr) { + line(54, 6)=fmt::LPaddedFloat(atom.GetCharge(), 2); + line(60, 6)=fmt::LPaddedFloat(atom.GetRadius(), 2); + } else { + line(54, 6)=fmt::LPaddedFloat(atom.GetOccupancy(), 2); + line(60, 6)=fmt::LPaddedFloat(atom.GetBFactor(), 2); + } + + line(76, 2)=fmt::LPadded(atom.GetElement()); + ostr << line; } } + + line.Clear(); } void write_conect(std::ostream& ostr, int atom_index, @@ -109,35 +168,63 @@ void write_conect(std::ostream& ostr, int atom_index, class PDBWriterImpl : public mol::EntityVisitor { public: - PDBWriterImpl(std::ostream& ostream, std::map<long,int>& atom_indices) - : ostr_(ostream), counter_(0), is_pqr_(false), last_chain_(), - atom_indices_(atom_indices) { + PDBWriterImpl(std::ostream& ostream, FormattedLine& line, + std::map<long,int>& atom_indices) + : ostr_(ostream), counter_(0), is_pqr_(false), + atom_indices_(atom_indices), line_(line), peptide_(false) { } private: public: virtual bool VisitAtom(const mol::AtomHandle& atom) { counter_++; - if (last_chain_!=atom.GetResidue().GetChain()) { - if (last_chain_.IsValid()) { - ostr_ << "TER" << std::endl; - } - last_chain_=atom.GetResidue().GetChain(); - } - write_atom(ostr_, atom, counter_, is_pqr_); + write_atom(ostr_, line_, atom, counter_, is_pqr_); if (atom.GetAtomProps().is_hetatm) { atom_indices_[atom.GetHashCode()]=counter_; } return true; } + + virtual bool VisitResidue(const mol::ResidueHandle& res) + { + if (res.IsPeptideLinking()) { + peptide_=true; + } else { + if (peptide_) { + this->WriteTer(prev_); + } + peptide_=false; + } + prev_=res; + return true; + } + + void WriteTer(mol::ResidueHandle res) + { + counter_++; + line_(0, 6)=StringRef("TER ", 6); + line_( 6, 5)=fmt::LPaddedInt(counter_); + line_(17, 3)=fmt::LPadded(res.GetKey()); + line_[21]=res.GetChain().GetName()[0]; + line_(22, 4)=fmt::LPaddedInt(res.GetNumber().GetNum()); + char ins_code=res.GetNumber().GetInsCode(); + if (ins_code!=0) { + line_[26]=ins_code; + } + ostr_ << line_; + line_.Clear(); + } + void SetIsPQR(bool t) { is_pqr_=t; } private: - std::ostream& ostr_; - int counter_; - bool is_pqr_; - mol::ChainHandle last_chain_; + std::ostream& ostr_; + int counter_; + bool is_pqr_; std::map<long,int>& atom_indices_; + FormattedLine& line_; + mol::ResidueHandle prev_; + bool peptide_; }; class PDBConectWriterImpl : public mol::EntityVisitor { @@ -172,18 +259,32 @@ private: std::map<long,int>& atom_indices_; }; +struct ForcePOSIX { + std::locale old_locale; + ForcePOSIX(){ + old_locale=std::locale(); + setlocale(LC_NUMERIC, "POSIX"); + } + ~ForcePOSIX(){ + setlocale(LC_NUMERIC, old_locale.name().c_str()); + } +}; + } PDBWriter::PDBWriter(std::ostream& stream): - outfile_(), outstream_(stream) -{} + outfile_(), outstream_(stream), mol_count_(0), line_(80) +{ + +} PDBWriter::PDBWriter(const boost::filesystem::path& filename): - outfile_(filename.file_string().c_str()), outstream_(outfile_), mol_count_(0) + outfile_(filename.file_string().c_str()), outstream_(outfile_), + mol_count_(0), line_(80) {} PDBWriter::PDBWriter(const String& filename): - outfile_(filename.c_str()), outstream_(outfile_), mol_count_(0) + outfile_(filename.c_str()), outstream_(outfile_), mol_count_(0), line_(80) {} void PDBWriter::WriteModelLeader() @@ -207,8 +308,9 @@ void PDBWriter::WriteModelTrailer() template <typename H> void PDBWriter::WriteModel(H ent) { + ForcePOSIX posix = ForcePOSIX(); this->WriteModelLeader(); - PDBWriterImpl writer(outstream_,atom_indices_); + PDBWriterImpl writer(outstream_,line_, atom_indices_); if (PDB::Flags() & PDB::PQR_FORMAT) { writer.SetIsPQR(true); } @@ -230,19 +332,13 @@ void PDBWriter::Write(const mol::EntityHandle& ent) void PDBWriter::Write(const mol::AtomHandleList& atoms) { + ForcePOSIX posix = ForcePOSIX(); this->WriteModelLeader(); int counter=1; mol::ChainHandle last_chain; for (mol::AtomHandleList::const_iterator i=atoms.begin(), e=atoms.end(); i!=e; ++i, ++counter) { - - if (last_chain!=(*i).GetResidue().GetChain()) { - if (last_chain.IsValid()) { - outstream_ << "TER" << std::endl; - } - last_chain=(*i).GetResidue().GetChain(); - } - write_atom(outstream_, *i, counter, PDB::Flags() & PDB::PQR_FORMAT); + write_atom(outstream_, line_, *i, counter, (PDB::Flags() & PDB::PQR_FORMAT) != 0); } this->WriteModelTrailer(); } diff --git a/modules/io/src/mol/pdb_writer.hh b/modules/io/src/mol/pdb_writer.hh index 68a9332a95587b79afe16caea37ca72414de52ec..40ed1cbffa5cf8094f8a5ab04cd366500414a445 100644 --- a/modules/io/src/mol/pdb_writer.hh +++ b/modules/io/src/mol/pdb_writer.hh @@ -28,9 +28,11 @@ #include <boost/filesystem/fstream.hpp> #include <boost/iostreams/filtering_stream.hpp> +#include <ost/mol/mol.hh> + #include <ost/io/module_config.hh> +#include <ost/io/formatted_line.hh> -#include <ost/mol/mol.hh> #include "pdb_io.hh" @@ -58,6 +60,7 @@ private: std::ostream& outstream_; int mol_count_; std::map<long, int> atom_indices_; + FormattedLine line_; }; }} diff --git a/modules/io/src/mol/sdf_reader.cc b/modules/io/src/mol/sdf_reader.cc new file mode 100644 index 0000000000000000000000000000000000000000..e2f0fabd24c65e33cf31664f8751d2208f60a096 --- /dev/null +++ b/modules/io/src/mol/sdf_reader.cc @@ -0,0 +1,275 @@ +//------------------------------------------------------------------------------ +// This file is part of the OpenStructure project <www.openstructure.org> +// +// Copyright (C) 2008-2010 by the OpenStructure authors +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation; either version 3.0 of the License, or (at your option) +// any later version. +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +//------------------------------------------------------------------------------ +/* + Author: Tobias Schmidt + */ + +#include <boost/algorithm/string.hpp> +#include <boost/format.hpp> +#include <boost/lexical_cast.hpp> + +#include <ost/conop/conop.hh> +#include <ost/io/io_exception.hh> +#include <ost/log.hh> +#include <ost/mol/xcs_editor.hh> + +#include "sdf_reader.hh" + +namespace ost { namespace io { + +using boost::format; + +SDFReader::SDFReader(const String& filename) + : infile_(filename), instream_(infile_) { + this->ClearState(); +} + +SDFReader::SDFReader(const boost::filesystem::path& loc) + : infile_(loc), instream_(infile_) { + this->ClearState(); +} + +SDFReader::SDFReader(std::istream& instream) + : infile_(), instream_(instream) { + this->ClearState(); +} + +// import data from provided stream +void SDFReader::Import(mol::EntityHandle& ent) +{ + String line; + mol::XCSEditor editor=ent.RequestXCSEditor(mol::BUFFERED_EDIT); + while (std::getline(instream_,line)) { + ++line_num; + + if (line_num<=4) { + ParseAndAddHeader(line, line_num, ent, editor); + } else if (line_num<=atom_count_+4) { + ParseAndAddAtom(line, line_num, ent, true, editor); + } else if (line_num<=bond_count_+atom_count_+4) { + ParseAndAddBond(line, line_num, ent, editor); + } else if (boost::iequals(line.substr(0,2), "> ")) { + // parse data items + int data_header_start = line.find('<'); + if(data_header_start==-1) { + String msg="Bad data line %d: Could not find start or end of header"; + throw IOException(str(format(msg) % line_num)); + } + String data_header = line.substr(data_header_start+1,line.rfind('>')-data_header_start-1); + if(data_header.empty()) { + String msg="Bad data line %d: Could not find data header"; + throw IOException(str(format(msg) % line_num)); + } + String data_value=""; + while(std::getline(instream_,line) && !boost::iequals(line, "")) { + data_value.append(line); + } + curr_chain_.SetStringProp(data_header, data_value); + } else if (boost::iequals(line, "$$$$")) { + LOGN_MESSAGE("MOLECULE " << curr_chain_.GetName() << " (" << chain_count_ << ") added.") + NextMolecule(); + } + } + + LOGN_MESSAGE("imported " << chain_count_ << " chains, " << residue_count_ + << " residues, " << atom_count_ << " atoms"); +} + +void SDFReader::ClearState() +{ + curr_chain_=mol::ChainHandle(); + curr_residue_=mol::ResidueHandle(); + chain_count_=0; + residue_count_=0; + atom_count_=0; + bond_count_=0; + line_num=0; +} + +void SDFReader::NextMolecule() +{ + residue_count_=0; + atom_count_=0; + bond_count_=0; + line_num=0; +} + +void SDFReader::ParseAndAddHeader(const String& line, int line_num, + mol::EntityHandle& ent, mol::XCSEditor& editor) +{ + LOGN_TRACE( "line: [" << line << "]" ); + format chain_fmter("%05i_%s"); + switch(line_num) + { + case 1: // title line + { + ++chain_count_; + String s_title=line; + String s_chain; + chain_fmter % chain_count_ % boost::trim_copy(s_title); + s_chain=chain_fmter.str(); + if(s_chain.empty()) { + String msg="Bad molecule name line %d: Line is empty"; + throw IOException(str(format(msg) % line_num)); + } + curr_chain_=editor.InsertChain(s_chain); + LOGN_DUMP("new chain " << s_chain); + + mol::ResidueKey rkey=boost::trim_copy(s_title); + mol::ResNum rnum(++residue_count_); + curr_residue_=editor.AppendResidue(curr_chain_, rkey, rnum); + LOGN_DUMP("new residue " << rkey << "(" << rnum << ")"); + break; + } + case 2: // user information line + break; + case 3: // comments line + break; + case 4: // counts line + { + String s_anum=line.substr(0,3); + try { + atom_count_=boost::lexical_cast<int>(boost::trim_copy(s_anum)); + } catch(boost::bad_lexical_cast&) { + String msg="Bad counts line %d: Can't convert number of atoms" + " '%s' to integral constant."; + throw IOException(str(format(msg) % line_num % s_anum)); + } + String s_bnum=line.substr(3,3); + try { + bond_count_=boost::lexical_cast<int>(boost::trim_copy(s_bnum)); + } catch(boost::bad_lexical_cast&) { + String msg="Bad counts line %d: Can't convert number of bonds" + " '%s' to integral constant."; + throw IOException(str(format(msg) % line_num % s_bnum)); + } + break; + } + } +} + +void SDFReader::ParseAndAddAtom(const String& line, int line_num, + mol::EntityHandle& ent, bool hetatm, + mol::XCSEditor& editor) +{ + + LOGN_TRACE( "line: [" << line << "]" ); + + if(line.length()<48 || line.length()>69) { + String msg="Bad atom line %d: Not correct number of characters on the" + " line: %i (should be between 48 and 69)"; + throw IOException(str(format(msg) % line_num % line.length())); + } + int anum = line_num-4; // start at 1 on fifth line since first four lines are header + String s_posx=line.substr(0,10); + String s_posy=line.substr(10,10); + String s_posz=line.substr(20,10); + String s_ele=line.substr(31,3); + String s_charge=line.substr(36,3); + + geom::Vec3 apos; + try { + apos=geom::Vec3(boost::lexical_cast<Real>(boost::trim_copy(s_posx)), + boost::lexical_cast<Real>(boost::trim_copy(s_posy)), + boost::lexical_cast<Real>(boost::trim_copy(s_posz))); + } catch(boost::bad_lexical_cast&) { + String msg="Bad atom line %d: Can't convert coordinates to " + "floating point numbers"; + throw IOException(str(format(msg) % line_num)); + } + + String ele=boost::trim_copy(s_ele); + String aname=boost::lexical_cast<String>(anum); + + mol::AtomProp aprop; + aprop.element=ele; + aprop.radius=conop::Conopology::Instance().GetDefaultAtomRadius(ele); + aprop.mass=conop::Conopology::Instance().GetDefaultAtomMass(ele); + aprop.is_hetatm=hetatm; + + try { + aprop.charge=boost::lexical_cast<Real>(boost::trim_copy(s_charge)); + if(aprop.charge != 0) { + aprop.charge=4-aprop.charge; + } //4-sdf_charge=real_charge if not 0 + } catch(boost::bad_lexical_cast&) { + String msg="Bad atom line %d: Can't convert charge" + " '%s' to integral constant."; + throw IOException(str(format(msg) % line_num % s_charge)); + } + + LOGN_DUMP("adding atom " << aname << " (" << s_ele << ") @" << apos); + + editor.InsertAtom(curr_residue_, aname,apos,aprop); +} + + +void SDFReader::ParseAndAddBond(const String& line, int line_num, + mol::EntityHandle& ent, mol::XCSEditor& editor) +{ + + LOGN_TRACE( "line: [" << line << "]" ); + + if(line.length()<18 || line.length()>21) { + String msg="Bad bond line %d: Not correct number of characters on the" + " line: %i (should be between 18 and 21)"; + throw IOException(str(format(msg) % line_num % line.length())); + } + + String s_first_name=line.substr(0,3); + String s_second_name=line.substr(3,3); + String s_type=line.substr(6,3); + String first_name, second_name; + unsigned char type; + mol::BondHandle bond; + + first_name=boost::trim_copy(s_first_name); + second_name=boost::trim_copy(s_second_name); + + try { + type=boost::lexical_cast<int>(boost::trim_copy(s_type)); + if (type<1 || type>8) { + String msg="Bad bond line %d: Bond type number" + " '%s' not within accepted range (1-8)."; + throw IOException(str(format(msg) % line_num % s_type)); + } + } catch(boost::bad_lexical_cast&) { + String msg="Bad bond line %d: Can't convert bond type number" + " '%s' to integral constant."; + throw IOException(str(format(msg) % line_num % s_type)); + } + + mol::AtomHandle first,second; + + first = ent.FindAtom(curr_chain_.GetName(), mol::ResNum(residue_count_), first_name); + second = ent.FindAtom(curr_chain_.GetName(), mol::ResNum(residue_count_), second_name); + + if(first.IsValid() && second.IsValid()) { + bond = editor.Connect(first, second); + bond.SetBondOrder(type); + } else { + String msg="Bad bond line %d: Can't find the atom names '%s', '%s'" + " in entity."; + throw IOException(str(format(msg) % line_num % first % second)); + } + + LOGN_DUMP("adding bond " << s_first_name << " " << s_second_name << " (" << s_type << ") "); +} + +}} diff --git a/modules/io/src/mol/sdf_reader.hh b/modules/io/src/mol/sdf_reader.hh new file mode 100644 index 0000000000000000000000000000000000000000..0401e6ab746b3a0a86c738599071ecb5b50f6b79 --- /dev/null +++ b/modules/io/src/mol/sdf_reader.hh @@ -0,0 +1,67 @@ +//------------------------------------------------------------------------------ +// This file is part of the OpenStructure project <www.openstructure.org> +// +// Copyright (C) 2008-2010 by the OpenStructure authors +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation; either version 3.0 of the License, or (at your option) +// any later version. +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +//------------------------------------------------------------------------------ +/* + Author: Tobias Schmidt + */ +#ifndef OST_IO_SDF_READER_HH +#define OST_IO_SDF_READER_HH + +#include <boost/filesystem/fstream.hpp> +#include <ost/mol/mol.hh> +#include <ost/io/module_config.hh> + +namespace ost { namespace io { + +class DLLEXPORT_OST_IO SDFReader { +public: + SDFReader(const String& filename); + SDFReader(const boost::filesystem::path& loc); + SDFReader(std::istream& instream); + + bool HasNext(); + + void Import(mol::EntityHandle& ent); + +private: + void ClearState(); + void NextMolecule(); + + void ParseAndAddHeader(const String& line, int line_num, mol::EntityHandle& ent, + mol::XCSEditor& editor); + + void ParseAndAddAtom(const String& line, int line_num, mol::EntityHandle& ent, + bool hetatm, mol::XCSEditor& editor); + + void ParseAndAddBond(const String& line, int line_num, mol::EntityHandle& ent, + mol::XCSEditor& editor); + + mol::ChainHandle curr_chain_; + mol::ResidueHandle curr_residue_; + int chain_count_; + int residue_count_; + int atom_count_; + int bond_count_; + int line_num; + boost::filesystem::ifstream infile_; + std::istream& instream_; +}; + +}} + +#endif diff --git a/modules/io/src/mol/sdf_writer.cc b/modules/io/src/mol/sdf_writer.cc new file mode 100644 index 0000000000000000000000000000000000000000..b6243b4a698cb9959904f67c67256b9bdf14ceb1 --- /dev/null +++ b/modules/io/src/mol/sdf_writer.cc @@ -0,0 +1,158 @@ +//------------------------------------------------------------------------------ +// This file is part of the OpenStructure project <www.openstructure.org> +// +// Copyright (C) 2008-2010 by the OpenStructure authors +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation; either version 3.0 of the License, or (at your option) +// any later version. +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +//------------------------------------------------------------------------------ +/* + Author: Tobias Schmidt + */ + +#include "sdf_writer.hh" + +namespace ost { namespace io { + +using boost::format; + +namespace { + + class SDFAtomWriter : public mol::EntityVisitor { + public: + SDFAtomWriter(std::ostream& ostream, std::map<long, int>& atom_indices) + : ostr_(ostream), atom_indices_(atom_indices), counter_(0) { + atom_indices_.clear(); + } + private: + public: + virtual bool VisitAtom(const mol::AtomHandle& atom) { + atom_indices_[atom.GetHashCode()] = ++counter_; + ostr_ << format("%10.4f") % atom.GetPos()[0] + << format("%10.4f") % atom.GetPos()[1] + << format("%10.4f ") % atom.GetPos()[2] + << format("%-3s") % atom.GetElement() + << " 0 0 0 0 0 0" + << std::endl; + return true; + } + private: + std::ostream& ostr_; + std::map<long, int>& atom_indices_; + int counter_; + }; + + class SDFBondWriter : public mol::EntityVisitor { + public: + SDFBondWriter(std::ostream& ostream, std::map<long, int>& atom_indices) + : ostr_(ostream), atom_indices_(atom_indices), counter_(0) { + } + private: + public: + virtual bool VisitAtom(const mol::AtomHandle& atom) { + counter_++; + mol::AtomHandleList atoms = atom.GetBondPartners(); + mol::AtomHandleList::iterator atom_iter = atoms.begin(); + for(; atom_iter != atoms.end(); ++atom_iter) { + int atom_index = atom_indices_.find((*atom_iter).GetHashCode())->second; + if(atom_index > counter_) { + int type = 1; + mol::BondHandle bond = atom.FindBondToAtom(*atom_iter); + if(bond.IsValid()) type = bond.GetBondOrder(); + ostr_ << format("%3i") % counter_ + << format("%3i") % atom_index + << format("%3i") % type + << " 0 0 0" + << std::endl; + } + } + return true; + } + + private: + std::ostream& ostr_; + std::map<long, int>& atom_indices_; + int counter_; + }; +} + +SDFWriter::SDFWriter(std::ostream& ostream) + : outfile_(), ostr_(ostream), counter_(0) { +} + +SDFWriter::SDFWriter(const String& filename) + : outfile_(filename.c_str()), ostr_(outfile_), counter_(0) { +} + +SDFWriter::SDFWriter(const boost::filesystem::path& filename) + : outfile_(filename.file_string().c_str()), ostr_(outfile_), counter_(0) { +} + +void SDFWriter::Write(const mol::EntityView& ent) { + mol::EntityView non_const_view = ent; + non_const_view.Apply(*this); +} + +void SDFWriter::Write(const mol::EntityHandle& ent) { + mol::EntityHandle non_const_handle = ent; + non_const_handle.Apply(*this); +} + +bool SDFWriter::VisitChain(const mol::ChainHandle& chain) { + // print end of molecule line + if(counter_ != 0) { + ostr_ << "$$$$" << std::endl; + counter_ = 0; + atom_indices_.clear(); + } + + // print header lines + ostr_ << chain.GetName().substr(6) << std::endl; + ostr_ << std::endl; + ostr_ << std::endl; + + // print counts line + ostr_ << format("%3d") % chain.GetAtomCount() + << format("%3d") % chain.GetBondCount() + << " 0 0 0 0 999 V2000" + << std::endl; + + // write atom block + SDFAtomWriter atom_writer(ostr_, atom_indices_); + mol::ChainHandle non_const_chain = chain; + non_const_chain.Apply(atom_writer); + + // write bond block + SDFBondWriter bond_writer(ostr_, atom_indices_); + non_const_chain.Apply(bond_writer); + + // write property block + //TODO: write property block + ostr_ << "M END" << std::endl; + + // write data block + std::map<String,GenericPropValue> prop_map = non_const_chain.GetPropMap(); + std::map<String,GenericPropValue>::iterator iter; + for(iter = prop_map.begin(); iter != prop_map.end(); ++iter) { + ostr_ << "> <" << (*iter).first << ">" << std::endl; + ostr_ << (*iter).second << std::endl; + ostr_ << std::endl; + } + + // write molecule endline + ostr_ << "$$$$" << std::endl; + + return true; +} + +}} diff --git a/modules/io/src/mol/sdf_writer.hh b/modules/io/src/mol/sdf_writer.hh new file mode 100644 index 0000000000000000000000000000000000000000..62a365d491f303f6e0a5a01add5ce3af1636deba --- /dev/null +++ b/modules/io/src/mol/sdf_writer.hh @@ -0,0 +1,61 @@ +//------------------------------------------------------------------------------ +// This file is part of the OpenStructure project <www.openstructure.org> +// +// Copyright (C) 2008-2010 by the OpenStructure authors +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation; either version 3.0 of the License, or (at your option) +// any later version. +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +//------------------------------------------------------------------------------ +/* + Author: Tobias Schmidt + */ +#ifndef OST_IO_SDF_WRITER_HH +#define OST_IO_SDF_WRITER_HH + +#include <iostream> +#include <sstream> +#include <iomanip> + +#include <boost/filesystem/fstream.hpp> +#include <boost/filesystem/convenience.hpp> +#include <boost/algorithm/string.hpp> +#include <boost/lexical_cast.hpp> +#include <boost/format.hpp> +#include <ost/log.hh> +#include <ost/conop/conop.hh> +#include <ost/io/io_exception.hh> +#include <ost/mol/mol.hh> + +namespace ost { namespace io { + +class DLLEXPORT_OST_IO SDFWriter : public mol::EntityVisitor { +public: + SDFWriter(std::ostream& ostream); + SDFWriter(const String& filename); + SDFWriter(const boost::filesystem::path& filename); + + void Write(const mol::EntityView& ent); + void Write(const mol::EntityHandle& ent); + +private: + virtual bool VisitChain(const mol::ChainHandle& chain); + + std::ofstream outfile_; + std::ostream& ostr_; + int counter_; + std::map<long,int> atom_indices_; +}; + +}} + +#endif diff --git a/modules/io/tests/test_io_pdb.cc b/modules/io/tests/test_io_pdb.cc index 811c459a891d1f08e8400242ef896979a3829fbb..3b9b691c31b5299da339a02b4e6d5aaec31d6344 100644 --- a/modules/io/tests/test_io_pdb.cc +++ b/modules/io/tests/test_io_pdb.cc @@ -16,9 +16,12 @@ // along with this library; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA //------------------------------------------------------------------------------ +#include <ost/test_utils/compare_files.hh> #include <ost/mol/mol.hh> +#include <ost/conop/conop.hh> #include <ost/io/mol/entity_io_pdb_handler.hh> #include <ost/io/pdb_reader.hh> +#include <ost/io/pdb_writer.hh> #include <ost/io/io_exception.hh> #define BOOST_TEST_DYN_LINK #include <boost/test/unit_test.hpp> @@ -160,18 +163,17 @@ BOOST_AUTO_TEST_CASE(anisou_record) mol::AtomHandle a1=ent.FindAtom("A", mol::ResNum(7), "N"); BOOST_REQUIRE(a1.IsValid()); mol::AtomProp props=a1.GetAtomProps(); - BOOST_CHECK_CLOSE( 0.0100, props.anisou(0, 0), 1e-4); - BOOST_CHECK_CLOSE(-0.0016, props.anisou(1, 0), 1e-4); - BOOST_CHECK_CLOSE(-0.0026, props.anisou(2, 0), 1e-4); - BOOST_CHECK_CLOSE(-0.0016, props.anisou(0, 1), 1e-4); - BOOST_CHECK_CLOSE( 0.0110, props.anisou(1, 1), 1e-4); - BOOST_CHECK_CLOSE(-0.0054, props.anisou(2, 1), 1e-4); - BOOST_CHECK_CLOSE(-0.0026, props.anisou(0, 2), 1e-4); - BOOST_CHECK_CLOSE(-0.0054, props.anisou(1, 2), 1e-4); - BOOST_CHECK_CLOSE( 0.0120, props.anisou(2, 2), 1e-4); + BOOST_CHECK_CLOSE(Real( 0.0100), props.anisou(0, 0), Real(1e-4)); + BOOST_CHECK_CLOSE(Real(-0.0016), props.anisou(1, 0), Real(1e-4)); + BOOST_CHECK_CLOSE(Real(-0.0026), props.anisou(2, 0), Real(1e-4)); + BOOST_CHECK_CLOSE(Real(-0.0016), props.anisou(0, 1), Real(1e-4)); + BOOST_CHECK_CLOSE(Real( 0.0110), props.anisou(1, 1), Real(1e-4)); + BOOST_CHECK_CLOSE(Real(-0.0054), props.anisou(2, 1), Real(1e-4)); + BOOST_CHECK_CLOSE(Real(-0.0026), props.anisou(0, 2), Real(1e-4)); + BOOST_CHECK_CLOSE(Real(-0.0054), props.anisou(1, 2), Real(1e-4)); + BOOST_CHECK_CLOSE(Real( 0.0120), props.anisou(2, 2), Real(1e-4)); } - BOOST_AUTO_TEST_CASE(only_66_cols) { String fname("testfiles/pdb/short.pdb"); @@ -186,7 +188,54 @@ BOOST_AUTO_TEST_CASE(no_endmdl_record) PDBReader reader(fname); mol::EntityHandle ent=mol::CreateEntity(); BOOST_CHECK_THROW(reader.Import(ent), IOException); +} +BOOST_AUTO_TEST_CASE(write_atom) +{ + std::stringstream out; + PDBWriter writer(out); + + mol::EntityHandle ent=mol::CreateEntity(); + mol::XCSEditor edi=ent.RequestXCSEditor(); + mol::ChainHandle ch=edi.InsertChain("A"); + mol::ResidueHandle r=edi.AppendResidue(ch, "GLY"); + mol::AtomProp c_prop; + c_prop.element="C"; + c_prop.occupancy=1.0; + c_prop.b_factor=128.0; + mol::AtomHandle a=edi.InsertAtom(r, "CA", geom::Vec3(32.0, -128.0, -2.5), + c_prop); + writer.Write(ent); + String s=out.str(); + BOOST_CHECK_EQUAL(s.substr(0, 54), + "ATOM 1 CA GLY A 1 32.000-128.000 -2.500"); + BOOST_CHECK_EQUAL(s.substr(54, 26), + " 1.00128.00 C "); +} + +BOOST_AUTO_TEST_CASE(write_hetatom) +{ + std::stringstream out; + PDBWriter writer(out); + + mol::EntityHandle ent=mol::CreateEntity(); + mol::XCSEditor edi=ent.RequestXCSEditor(); + mol::ChainHandle ch=edi.InsertChain("A"); + mol::ResidueHandle r=edi.AppendResidue(ch, "CA"); + mol::AtomProp c_prop; + c_prop.element="CA"; + c_prop.is_hetatm=true; + c_prop.mass=40.01; + c_prop.occupancy=1.0; + c_prop.b_factor=40.75; + mol::AtomHandle a=edi.InsertAtom(r, "CA", geom::Vec3(32.0, -128.0, -2.5), + c_prop); + writer.Write(ent); + String s=out.str(); + BOOST_CHECK_EQUAL(s.substr(0, 54), + "HETATM 1 CA CA A 1 32.000-128.000 -2.500"); + BOOST_CHECK_EQUAL(s.substr(54, 26), + " 1.00 40.75 CA "); } BOOST_AUTO_TEST_CASE(no_endmdl_record_fault_tolerant) @@ -207,4 +256,98 @@ BOOST_AUTO_TEST_CASE(no_endmdl_record_fault_tolerant) PDB::PopFlags(); } +BOOST_AUTO_TEST_CASE(alt_loc_import_export) +{ + String fname("testfiles/pdb/alt-loc.pdb"); + // this scope is required to force the writer stream to be closed before + // opening the file again in compare_files. Avoids a race condition. + { + PDBReader reader(fname); + PDBWriter writer(String("testfiles/pdb/alt-loc-out.pdb")); + + mol::EntityHandle ent=mol::CreateEntity(); + reader.Import(ent); + writer.Write(ent); + } + BOOST_CHECK(compare_files("testfiles/pdb/alt-loc.pdb", + "testfiles/pdb/alt-loc-out.pdb")); +} + +BOOST_AUTO_TEST_CASE(write_ter) +{ + String fname("testfiles/pdb/ter.pdb"); + // this scope is required to force the writer stream to be closed before + // opening the file again in compare_files. Avoids a race condition. + { + PDBReader reader(fname); + PDBWriter writer(String("testfiles/pdb/ter-out.pdb")); + + mol::EntityHandle ent=mol::CreateEntity(); + reader.Import(ent); + // we use conopology to mark amino acids as peptide-linking. this is require + // for proper TER output + conop::Conopology& conop_inst=conop::Conopology::Instance(); + conop_inst.ConnectAll(conop_inst.GetBuilder(), ent); + writer.Write(ent); + } + BOOST_CHECK(compare_files("testfiles/pdb/ter.pdb", + "testfiles/pdb/ter-out.pdb")); +} + +BOOST_AUTO_TEST_CASE(write_conect) +{ + // this scope is required to force the writer stream to be closed before + // opening the file again in compare_files. Avoids a race condition. + { + PDBReader reader(String("testfiles/pdb/conect.pdb")); + PDBWriter writer(String("testfiles/pdb/conect-out.pdb")); + mol::EntityHandle ent=mol::CreateEntity(); + reader.Import(ent); + conop::Conopology& conop_inst=conop::Conopology::Instance(); + conop_inst.ConnectAll(conop_inst.GetBuilder(), ent); + writer.Write(ent); + } + BOOST_CHECK(compare_files("testfiles/pdb/conect.pdb", + "testfiles/pdb/conect-out.pdb")); +} + +BOOST_AUTO_TEST_CASE(res_name_too_long) +{ + std::stringstream out; + PDBWriter writer(out); + + mol::EntityHandle ent=mol::CreateEntity(); + mol::XCSEditor edi=ent.RequestXCSEditor(); + mol::ChainHandle ch=edi.InsertChain("A"); + mol::ResidueHandle r=edi.AppendResidue(ch, "CALCIUM"); + mol::AtomHandle a=edi.InsertAtom(r, "CA", geom::Vec3(32.0, -128.0, -2.5)); + BOOST_CHECK_THROW(writer.Write(ent), IOException); +} + +BOOST_AUTO_TEST_CASE(chain_name_too_long) +{ + std::stringstream out; + PDBWriter writer(out); + + mol::EntityHandle ent=mol::CreateEntity(); + mol::XCSEditor edi=ent.RequestXCSEditor(); + mol::ChainHandle ch=edi.InsertChain("AB"); + mol::ResidueHandle r=edi.AppendResidue(ch, "CA"); + mol::AtomHandle a=edi.InsertAtom(r, "CA", geom::Vec3(32.0, -128.0, -2.5)); + BOOST_CHECK_THROW(writer.Write(ent), IOException); +} + +BOOST_AUTO_TEST_CASE(atom_name_too_long) +{ + std::stringstream out; + PDBWriter writer(out); + + mol::EntityHandle ent=mol::CreateEntity(); + mol::XCSEditor edi=ent.RequestXCSEditor(); + mol::ChainHandle ch=edi.InsertChain("A"); + mol::ResidueHandle r=edi.AppendResidue(ch, "CA"); + mol::AtomHandle a=edi.InsertAtom(r, "CALCIUM", geom::Vec3(32.0, -128.0, -2.5)); + BOOST_CHECK_THROW(writer.Write(ent), IOException); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/modules/io/tests/test_io_sdf.cc b/modules/io/tests/test_io_sdf.cc index 71c773f39a55b9b615589d18ca8bf9eb80daf5e5..bbf858427da81a44a098a997b28682a1cb205073 100644 --- a/modules/io/tests/test_io_sdf.cc +++ b/modules/io/tests/test_io_sdf.cc @@ -16,33 +16,110 @@ // along with this library; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA //------------------------------------------------------------------------------ +#include <ost/test_utils/compare_files.hh> #include <ost/mol/mol.hh> #include <ost/io/mol/entity_io_sdf_handler.hh> +#include <ost/io/save_entity.hh> +#include <ost/io/io_exception.hh> #define BOOST_TEST_DYN_LINK #include <boost/test/unit_test.hpp> #include <boost/lexical_cast.hpp> #include <boost/algorithm/string.hpp> +using boost::unit_test_framework::test_suite; using namespace ost; using namespace ost::io; BOOST_AUTO_TEST_SUITE( io ) - -BOOST_AUTO_TEST_CASE(test_io_sdf) +BOOST_AUTO_TEST_CASE(test_sdf_import_handler) { - const String fname("testfiles/test_in.sdf"); + String fname("testfiles/sdf/compound.sdf"); mol::EntityHandle eh=mol::CreateEntity(); EntityIOSDFHandler sdfh; - // check format BOOST_CHECK(EntityIOSDFHandler::ProvidesImport("","sdf")); BOOST_CHECK(EntityIOSDFHandler::ProvidesImport(fname)); BOOST_CHECK(EntityIOSDFHandler::ProvidesImport("test_in.SDF")); + BOOST_CHECK(EntityIOSDFHandler::ProvidesExport("","sdf")); + BOOST_CHECK(EntityIOSDFHandler::ProvidesExport(fname)); + BOOST_CHECK(EntityIOSDFHandler::ProvidesExport("test_in.SDF")); + + sdfh.Import(eh,"testfiles/sdf/compound.sdf"); +} + +BOOST_AUTO_TEST_CASE(simple_sdf) +{ + mol::EntityHandle eh=mol::CreateEntity(); + EntityIOSDFHandler sdfh; + sdfh.Import(eh,"testfiles/sdf/simple.sdf"); + + // check compounds/atoms/bonds count + BOOST_CHECK_EQUAL(eh.GetChainCount(), 1); + BOOST_CHECK_EQUAL(eh.GetAtomCount(), 6); + BOOST_CHECK_EQUAL(eh.GetBondCount(), 6); + BOOST_CHECK_CLOSE(eh.GetMass(), Real(121.545502), Real(1e-4)); + + // check atom/bond types + mol::AtomHandle ah=eh.GetAtomList()[0]; + mol::AtomHandle ah2=eh.GetAtomList()[5]; + + BOOST_CHECK_EQUAL(ah.GetElement(), "N"); + BOOST_CHECK_EQUAL(ah2.GetElement(), "Cl"); + BOOST_CHECK_CLOSE(ah.GetRadius(), Real(1.55), Real(1e-2)); + BOOST_CHECK_CLOSE(ah2.GetRadius(), Real(1.75), Real(1e-2)); + BOOST_CHECK_CLOSE(ah.GetMass(), Real(14.0067), Real(1e-4)); + BOOST_CHECK_CLOSE(ah2.GetMass(), Real(35.453), Real(1e-3)); + BOOST_CHECK_EQUAL(ah.GetBondCount(), 3); + BOOST_CHECK_EQUAL(ah2.GetBondCount(), 1); + BOOST_CHECK_EQUAL(ah.GetCharge(), 1); + BOOST_CHECK_EQUAL(ah2.GetCharge(), 0); + + mol::BondHandle bh=ah.GetBondList()[0]; + BOOST_CHECK_EQUAL(bh.GetBondOrder(), 2); +} + +BOOST_AUTO_TEST_CASE(multiple_sdf) +{ + mol::EntityHandle eh=mol::CreateEntity(); + EntityIOSDFHandler sdfh; + sdfh.Import(eh,"testfiles/sdf/multiple.sdf"); + + // check number of compounds + BOOST_CHECK_EQUAL(eh.GetChainCount(), 4); +} + +BOOST_AUTO_TEST_CASE(properties_sdf) +{ + mol::EntityHandle eh=mol::CreateEntity(); + EntityIOSDFHandler sdfh; + sdfh.Import(eh,"testfiles/sdf/properties.sdf"); + + // check number of compounds + mol::ChainHandleList chl=eh.GetChainList(); + int count=1; + for (mol::ChainHandleList::iterator i=chl.begin();i!=chl.end();++i,count++) + { + BOOST_REQUIRE(i->HasProp("prop_one")); + BOOST_REQUIRE(i->HasProp("prop_two")); + BOOST_CHECK_CLOSE(boost::lexical_cast<Real>(i->GetStringProp("prop_one")), + Real(count),Real(1e-4)); + BOOST_CHECK_CLOSE(boost::lexical_cast<Real>(i->GetStringProp("prop_two")), + Real(count*(-2.2)),Real(1e-4)); + } +} + +BOOST_AUTO_TEST_CASE(read_sdf) +{ + const String fname("testfiles/sdf/compound.sdf"); + + mol::EntityHandle eh=mol::CreateEntity(); + EntityIOSDFHandler sdfh; + // check import - sdfh.Import(eh,"testfiles/test_in.sdf"); + sdfh.Import(eh,"testfiles/sdf/compound.sdf"); // check atoms/bonds BOOST_CHECK_EQUAL(eh.GetChainCount(), 4); @@ -50,14 +127,107 @@ BOOST_AUTO_TEST_CASE(test_io_sdf) BOOST_CHECK_EQUAL(eh.GetBondCount(), 188); // check molecule name - mol::ChainHandle ch=eh.FindChain("00003_Displayed atoms"); + mol::ChainHandle ch=eh.FindChain("00003_Test Ligand"); BOOST_CHECK(ch.IsValid()); // check properties BOOST_CHECK(ch.HasProp("r_i_glide_rmsd")); - BOOST_CHECK_EQUAL(boost::lexical_cast<Real>(boost::trim_copy + BOOST_CHECK_EQUAL(boost::lexical_cast<float>(boost::trim_copy (ch.GetStringProp("r_i_glide_rmsd"))), 0.543804f); } +BOOST_AUTO_TEST_CASE(write_sdf) +{ + // this scope is required to force the writer stream to be closed before + // opening the file again in compare_files. Avoids a race condition. + { + mol::EntityHandle eh=mol::CreateEntity(); + EntityIOSDFHandler sdfh; + sdfh.Import(eh,"testfiles/sdf/compound.sdf"); + SaveEntity(eh, "testfiles/sdf/compound-out.sdf"); + } + BOOST_CHECK(compare_files("testfiles/sdf/compound.sdf", + "testfiles/sdf/compound-out.sdf")); +} + +BOOST_AUTO_TEST_CASE(wrong_atomcount_error_sdf) +{ + mol::EntityHandle eh=mol::CreateEntity(); + EntityIOSDFHandler sdfh; + BOOST_CHECK_THROW(sdfh.Import(eh,"testfiles/sdf/wrong_atomcount.sdf"), IOException); +} + +BOOST_AUTO_TEST_CASE(wrong_bondcount_error_sdf) +{ + mol::EntityHandle eh=mol::CreateEntity(); + EntityIOSDFHandler sdfh; + BOOST_CHECK_THROW(sdfh.Import(eh,"testfiles/sdf/wrong_bondcount.sdf"), IOException); +} + +BOOST_AUTO_TEST_CASE(wrong_atomlinelength_error_sdf) +{ + mol::EntityHandle eh=mol::CreateEntity(); + EntityIOSDFHandler sdfh; + + BOOST_CHECK_THROW(sdfh.Import(eh,"testfiles/sdf/wrong_atomlinelength.sdf"), IOException); +} + +BOOST_AUTO_TEST_CASE(wrong_atompos_error_sdf) +{ + mol::EntityHandle eh=mol::CreateEntity(); + EntityIOSDFHandler sdfh; + + BOOST_CHECK_THROW(sdfh.Import(eh,"testfiles/sdf/wrong_atompos.sdf"), IOException); +} + +BOOST_AUTO_TEST_CASE(wrong_charge_error_sdf) +{ + mol::EntityHandle eh=mol::CreateEntity(); + EntityIOSDFHandler sdfh; + + BOOST_CHECK_THROW(sdfh.Import(eh,"testfiles/sdf/wrong_charge.sdf"), IOException); +} + +BOOST_AUTO_TEST_CASE(wrong_bondlinelength_error_sdf) +{ + mol::EntityHandle eh=mol::CreateEntity(); + EntityIOSDFHandler sdfh; + + BOOST_CHECK_THROW(sdfh.Import(eh,"testfiles/sdf/wrong_bondlinelength.sdf"), IOException); +} + +BOOST_AUTO_TEST_CASE(wrong_bondtype_error_sdf) +{ + mol::EntityHandle eh=mol::CreateEntity(); + EntityIOSDFHandler sdfh; + + BOOST_CHECK_THROW(sdfh.Import(eh,"testfiles/sdf/wrong_bondtype.sdf"), IOException); +} + +BOOST_AUTO_TEST_CASE(wrong_bondatomnumber_error_sdf) +{ + mol::EntityHandle eh=mol::CreateEntity(); + EntityIOSDFHandler sdfh; + + BOOST_CHECK_THROW(sdfh.Import(eh,"testfiles/sdf/wrong_bondatomnumber.sdf"), IOException); +} + +BOOST_AUTO_TEST_CASE(wrong_dataheader_error_sdf) +{ + mol::EntityHandle eh=mol::CreateEntity(); + EntityIOSDFHandler sdfh; + + BOOST_CHECK_THROW(sdfh.Import(eh,"testfiles/sdf/wrong_dataheader.sdf"), IOException); +} + +BOOST_AUTO_TEST_CASE(empty_dataheader_error_sdf) +{ + mol::EntityHandle eh=mol::CreateEntity(); + EntityIOSDFHandler sdfh; + + BOOST_CHECK_THROW(sdfh.Import(eh,"testfiles/sdf/empty_dataheader.sdf"), IOException); +} + + BOOST_AUTO_TEST_SUITE_END() diff --git a/modules/io/tests/testfiles/pdb/alt-loc.pdb b/modules/io/tests/testfiles/pdb/alt-loc.pdb new file mode 100644 index 0000000000000000000000000000000000000000..b08f834596a2ff3d094fe2964479beccdbf168c0 --- /dev/null +++ b/modules/io/tests/testfiles/pdb/alt-loc.pdb @@ -0,0 +1,3 @@ +ATOM 1 N AMET A 1 16.000 64.000 0.000 0.50 1.00 N +ATOM 1 N BMET A 1 8.000-128.000 0.000 0.50 1.00 N +END \ No newline at end of file diff --git a/modules/io/tests/testfiles/pdb/conect.pdb b/modules/io/tests/testfiles/pdb/conect.pdb new file mode 100644 index 0000000000000000000000000000000000000000..b4ce6bd8e3855a2a79ccdcfa6424bf6ad796525c --- /dev/null +++ b/modules/io/tests/testfiles/pdb/conect.pdb @@ -0,0 +1,46 @@ +ATOM 1 N VAL A 1 -8.585 17.971 25.103 0.50 11.44 N +ATOM 2 CA VAL A 1 -8.253 17.023 24.068 0.50 12.65 C +ATOM 3 C VAL A 1 -7.312 17.705 23.054 0.50 16.06 C +ATOM 4 O VAL A 1 -7.544 18.799 22.596 0.50 12.36 O +ATOM 5 CB VAL A 1 -9.457 16.377 23.387 0.50 12.94 C +ATOM 6 CG1 VAL A 1 -9.264 14.902 23.055 0.50 11.08 C +ATOM 7 CG2 VAL A 1 -10.739 16.533 24.224 0.50 13.21 C +ATOM 8 N VAL A 2 -6.277 16.910 22.755 0.50 16.75 N +ATOM 9 CA VAL A 2 -5.196 17.143 21.863 0.50 16.61 C +ATOM 10 C VAL A 2 -4.253 18.199 22.473 0.50 19.00 C +ATOM 11 O VAL A 2 -4.434 18.654 23.600 0.50 17.27 O +ATOM 12 CB VAL A 2 -5.589 17.486 20.437 0.50 18.24 C +ATOM 13 CG1 VAL A 2 -7.059 17.853 20.200 0.50 19.12 C +ATOM 14 CG2 VAL A 2 -4.672 18.535 19.802 0.50 14.29 C +TER 15 VAL A 2 +HETATM 16 N PS0 A 3 -11.234 16.802 30.197 0.50 7.63 N +HETATM 17 CA PS0 A 3 -11.284 16.497 28.779 0.50 6.15 C +HETATM 18 C PS0 A 3 -10.818 17.753 28.010 0.50 8.61 C +HETATM 19 OS PS0 A 3 -11.697 18.822 28.249 0.50 4.53 O +HETATM 20 CB PS0 A 3 -12.670 16.079 28.322 0.50 12.53 C +HETATM 21 CG PS0 A 3 -13.432 14.971 29.048 0.50 11.04 C +HETATM 22 CD1 PS0 A 3 -13.076 13.629 28.983 0.50 10.33 C +HETATM 23 CD2 PS0 A 3 -14.560 15.373 29.807 0.50 12.71 C +HETATM 24 CE1 PS0 A 3 -13.818 12.638 29.661 0.50 11.11 C +HETATM 25 CE2 PS0 A 3 -15.300 14.380 30.483 0.50 14.32 C +HETATM 26 CZ PS0 A 3 -14.917 13.043 30.412 0.50 10.61 C +HETATM 27 CM PS0 A 3 -9.405 18.196 28.546 0.50 6.25 C +HETATM 28 O HOH A 4 -3.126 40.621 48.726 1.00 47.60 O +HETATM 29 O HOH A 5 -2.279 35.565 45.117 1.00 43.93 O +HETATM 30 O HOH A 6 5.765 35.848 41.846 1.00 36.24 O +HETATM 31 O HOH A 7 -12.666 40.044 22.441 1.00 41.24 O +HETATM 32 O HOH A 8 -4.462 37.411 18.124 1.00 30.94 O +HETATM 33 O HOH A 9 -1.109 26.454 19.470 1.00 39.06 O +CONECT 16 17 +CONECT 17 16 18 20 +CONECT 18 17 19 27 +CONECT 19 18 +CONECT 20 17 21 +CONECT 21 20 22 23 +CONECT 22 21 24 +CONECT 23 21 25 +CONECT 24 22 26 +CONECT 25 23 26 +CONECT 26 24 25 +CONECT 27 18 +END \ No newline at end of file diff --git a/modules/io/tests/testfiles/pdb/ter.pdb b/modules/io/tests/testfiles/pdb/ter.pdb new file mode 100644 index 0000000000000000000000000000000000000000..fb85bb40350acded72722a6598b4b965409ec00f --- /dev/null +++ b/modules/io/tests/testfiles/pdb/ter.pdb @@ -0,0 +1,15 @@ +ATOM 1 N THR A 161 29.926 -12.642 -13.047 1.00 25.35 N +ATOM 2 CA THR A 161 29.978 -12.367 -11.602 1.00 25.36 C +ATOM 3 C THR A 161 29.215 -13.430 -10.777 1.00 27.67 C +ATOM 4 O THR A 161 29.065 -13.298 -9.552 1.00 26.09 O +ATOM 5 CB THR A 161 29.363 -11.029 -11.309 1.00 24.99 C +ATOM 6 OG1 THR A 161 28.023 -11.041 -11.744 1.00 22.56 O +ATOM 7 CG2 THR A 161 29.998 -9.872 -12.148 1.00 23.85 C +ATOM 8 N ALA A 162 28.657 -14.427 -11.463 1.00 28.77 N +ATOM 9 CA ALA A 162 28.111 -15.569 -10.810 1.00 30.99 C +ATOM 10 C ALA A 162 29.301 -16.453 -10.436 1.00 33.52 C +ATOM 11 O ALA A 162 29.230 -17.243 -9.498 1.00 36.04 O +ATOM 12 CB ALA A 162 27.155 -16.295 -11.713 1.00 30.93 C +TER 13 ALA A 162 +HETATM 14 O HOH A 164 25.516 0.940 27.392 1.00 38.40 O +END \ No newline at end of file diff --git a/modules/io/tests/testfiles/test_in.sdf b/modules/io/tests/testfiles/sdf/compound.sdf similarity index 97% rename from modules/io/tests/testfiles/test_in.sdf rename to modules/io/tests/testfiles/sdf/compound.sdf index 9d7bdcfc135ac1c763f0e48478554c9c23934508..66ddbb58970b3696e174c3fa257252269ae32f43 100644 --- a/modules/io/tests/testfiles/test_in.sdf +++ b/modules/io/tests/testfiles/sdf/compound.sdf @@ -1,7 +1,7 @@ -Displayed atoms - 3D - Structure written by MMmdl. - 45 47 0 0 1 0 999 V2000 +Test Ligand + + + 45 47 0 0 0 0 999 V2000 35.9455 5.9021 22.1706 C 0 0 0 0 0 0 34.6074 5.5226 22.4445 O 0 0 0 0 0 0 33.9561 6.2475 23.4088 C 0 0 0 0 0 0 @@ -95,32 +95,29 @@ Displayed atoms 26 27 1 0 0 0 27 45 1 0 0 0 M END +> <i_i_glide_confnum> +2 + > <i_i_glide_lignum> 1 -> <r_i_docking_score> --8.84426 +> <i_i_glide_posenum> +352 -> <r_i_glide_gscore> +> <r_i_docking_score> -8.84426 -> <r_i_glide_lipo> --2.84534 - -> <r_i_glide_hbond> --0.960751 - -> <r_i_glide_metal> --0 +> <r_i_glide_ecoul> +-16.1644 -> <r_i_glide_rewards> --0.799851 +> <r_i_glide_einternal> +6.78671 -> <r_i_glide_evdw> --46.0502 +> <r_i_glide_emodel> +-96.9661 -> <r_i_glide_ecoul> --16.1644 +> <r_i_glide_energy> +-62.2146 > <r_i_glide_erotb> 0.517993 @@ -128,38 +125,41 @@ M END > <r_i_glide_esite> -0.0291388 -> <r_i_glide_emodel> --96.9661 +> <r_i_glide_evdw> +-46.0502 -> <r_i_glide_energy> --62.2146 +> <r_i_glide_gscore> +-8.84426 -> <r_i_glide_einternal> -6.78671 +> <r_i_glide_hbond> +-0.960751 > <r_i_glide_ligand_efficiency> -0.327565 +> <r_i_glide_ligand_efficiency_ln> +-2.0588 + > <r_i_glide_ligand_efficiency_sa> -0.982695 -> <r_i_glide_ligand_efficiency_ln> --2.0588 +> <r_i_glide_lipo> +-2.84534 -> <i_i_glide_confnum> -2 +> <r_i_glide_metal> +-0 -> <i_i_glide_posenum> -352 +> <r_i_glide_rewards> +-0.799851 > <r_i_glide_rmsd> 0.6819 $$$$ -Displayed atoms - 3D - Structure written by MMmdl. - 45 47 0 0 1 0 999 V2000 +Test Ligand + + + 45 47 0 0 0 0 999 V2000 34.3938 4.9895 21.4537 C 0 0 0 0 0 0 34.9786 5.7318 22.5298 O 0 0 0 0 0 0 34.1450 6.3862 23.4047 C 0 0 0 0 0 0 @@ -253,32 +253,29 @@ Displayed atoms 26 27 1 0 0 0 27 45 1 0 0 0 M END +> <i_i_glide_confnum> +14 + > <i_i_glide_lignum> 1 -> <r_i_docking_score> --8.79327 +> <i_i_glide_posenum> +302 -> <r_i_glide_gscore> +> <r_i_docking_score> -8.79327 -> <r_i_glide_lipo> --2.69167 - -> <r_i_glide_hbond> --0.966475 - -> <r_i_glide_metal> --0 +> <r_i_glide_ecoul> +-16.9687 -> <r_i_glide_rewards> --0.777126 +> <r_i_glide_einternal> +5.76514 -> <r_i_glide_evdw> --46.4187 +> <r_i_glide_emodel> +-98.4298 -> <r_i_glide_ecoul> --16.9687 +> <r_i_glide_energy> +-63.3874 > <r_i_glide_erotb> 0.517993 @@ -286,38 +283,41 @@ M END > <r_i_glide_esite> -0.00975737 -> <r_i_glide_emodel> --98.4298 +> <r_i_glide_evdw> +-46.4187 -> <r_i_glide_energy> --63.3874 +> <r_i_glide_gscore> +-8.79327 -> <r_i_glide_einternal> -5.76514 +> <r_i_glide_hbond> +-0.966475 > <r_i_glide_ligand_efficiency> -0.325677 +> <r_i_glide_ligand_efficiency_ln> +-2.04693 + > <r_i_glide_ligand_efficiency_sa> -0.97703 -> <r_i_glide_ligand_efficiency_ln> --2.04693 +> <r_i_glide_lipo> +-2.69167 -> <i_i_glide_confnum> -14 +> <r_i_glide_metal> +-0 -> <i_i_glide_posenum> -302 +> <r_i_glide_rewards> +-0.777126 > <r_i_glide_rmsd> 0.605551 $$$$ -Displayed atoms - 3D - Structure written by MMmdl. - 45 47 0 0 1 0 999 V2000 +Test Ligand + + + 45 47 0 0 0 0 999 V2000 36.2241 5.1749 22.8554 C 0 0 0 0 0 0 35.0609 5.8871 22.4479 O 0 0 0 0 0 0 34.2768 6.4601 23.4276 C 0 0 0 0 0 0 @@ -411,32 +411,29 @@ Displayed atoms 26 27 1 0 0 0 27 45 1 0 0 0 M END +> <i_i_glide_confnum> +1 + > <i_i_glide_lignum> 1 -> <r_i_docking_score> --8.70173 +> <i_i_glide_posenum> +177 -> <r_i_glide_gscore> +> <r_i_docking_score> -8.70173 -> <r_i_glide_lipo> --2.74283 - -> <r_i_glide_hbond> --0.97397 - -> <r_i_glide_metal> --0 +> <r_i_glide_ecoul> +-15.8862 -> <r_i_glide_rewards> --0.764823 +> <r_i_glide_einternal> +1.84397 -> <r_i_glide_evdw> --46.5538 +> <r_i_glide_emodel> +-99.0481 -> <r_i_glide_ecoul> --15.8862 +> <r_i_glide_energy> +-62.44 > <r_i_glide_erotb> 0.517993 @@ -444,38 +441,41 @@ M END > <r_i_glide_esite> -0.0274759 -> <r_i_glide_emodel> --99.0481 +> <r_i_glide_evdw> +-46.5538 -> <r_i_glide_energy> --62.44 +> <r_i_glide_gscore> +-8.70173 -> <r_i_glide_einternal> -1.84397 +> <r_i_glide_hbond> +-0.97397 > <r_i_glide_ligand_efficiency> -0.322286 +> <r_i_glide_ligand_efficiency_ln> +-2.02562 + > <r_i_glide_ligand_efficiency_sa> -0.966858 -> <r_i_glide_ligand_efficiency_ln> --2.02562 +> <r_i_glide_lipo> +-2.74283 -> <i_i_glide_confnum> -1 +> <r_i_glide_metal> +-0 -> <i_i_glide_posenum> -177 +> <r_i_glide_rewards> +-0.764823 > <r_i_glide_rmsd> 0.543804 $$$$ -Displayed atoms - 3D - Structure written by MMmdl. - 45 47 0 0 1 0 999 V2000 +Test Ligand + + + 45 47 0 0 0 0 999 V2000 36.1312 5.0238 22.8745 C 0 0 0 0 0 0 35.3492 6.1234 22.4285 O 0 0 0 0 0 0 34.5144 6.6833 23.3611 C 0 0 0 0 0 0 @@ -569,32 +569,29 @@ Displayed atoms 26 27 1 0 0 0 27 45 1 0 0 0 M END +> <i_i_glide_confnum> +9 + > <i_i_glide_lignum> 1 -> <r_i_docking_score> --8.69162 +> <i_i_glide_posenum> +294 -> <r_i_glide_gscore> +> <r_i_docking_score> -8.69162 -> <r_i_glide_lipo> --2.92829 - -> <r_i_glide_hbond> --0.870172 - -> <r_i_glide_metal> --0 +> <r_i_glide_ecoul> +-14.7519 -> <r_i_glide_rewards> --0.764823 +> <r_i_glide_einternal> +5.89466 -> <r_i_glide_evdw> --48.432 +> <r_i_glide_emodel> +-97.7232 -> <r_i_glide_ecoul> --14.7519 +> <r_i_glide_energy> +-63.1839 > <r_i_glide_erotb> 0.517993 @@ -602,29 +599,32 @@ M END > <r_i_glide_esite> -0.0119369 -> <r_i_glide_emodel> --97.7232 +> <r_i_glide_evdw> +-48.432 -> <r_i_glide_energy> --63.1839 +> <r_i_glide_gscore> +-8.69162 -> <r_i_glide_einternal> -5.89466 +> <r_i_glide_hbond> +-0.870172 > <r_i_glide_ligand_efficiency> -0.321912 +> <r_i_glide_ligand_efficiency_ln> +-2.02327 + > <r_i_glide_ligand_efficiency_sa> -0.965735 -> <r_i_glide_ligand_efficiency_ln> --2.02327 +> <r_i_glide_lipo> +-2.92829 -> <i_i_glide_confnum> -9 +> <r_i_glide_metal> +-0 -> <i_i_glide_posenum> -294 +> <r_i_glide_rewards> +-0.764823 > <r_i_glide_rmsd> 0.463026 diff --git a/modules/io/tests/testfiles/sdf/empty_dataheader.sdf b/modules/io/tests/testfiles/sdf/empty_dataheader.sdf new file mode 100644 index 0000000000000000000000000000000000000000..9de4a7b638af519d9e1e28480e0869d7b05ae1d5 --- /dev/null +++ b/modules/io/tests/testfiles/sdf/empty_dataheader.sdf @@ -0,0 +1,48 @@ +Simple Ligand 1 + + Teststructure + 6 6 0 0 1 0 999 V2000 + 0.0000 0.0000 0.0000 N 0 3 0 0 0 0 + 1.0000 0.0000 0.0000 C 0 0 0 0 0 0 + 0.0000 1.0000 0.0000 O 0 0 0 0 0 0 + 1.0000 1.0000 0.0000 S 0 0 0 0 0 0 + 2.0000 2.0000 0.0000 C 0 0 0 0 0 0 + -1.0000 -1.0000 0.0000 Cl 0 0 0 0 0 0 + 1 2 2 0 0 0 + 1 3 1 0 0 0 + 1 6 1 0 0 0 + 2 4 1 0 0 0 + 3 4 1 0 0 0 + 4 5 3 0 0 0 +M END +> <> +1 + +> <prop_two> +-2 + +$$$$ +Simple Ligand 2 + + Teststructure + 6 6 0 0 1 0 999 V2000 + 0.0000 0.0000 0.0000 N 0 3 0 0 0 0 + 1.0000 0.0000 0.0000 C 0 0 0 0 0 0 + 0.0000 1.0000 0.0000 O 0 0 0 0 0 0 + 1.0000 1.0000 0.0000 S 0 0 0 0 0 0 + 2.0000 2.0000 0.0000 C 0 0 0 0 0 0 + -1.0000 -1.0000 0.0000 Cl 0 0 0 0 0 0 + 1 2 2 0 0 0 + 1 3 1 0 0 0 + 1 6 1 0 0 0 + 2 4 1 0 0 0 + 3 4 1 0 0 0 + 4 5 3 0 0 0 +M END +> <prop_one> +2 + +> <prop_two> +-4 + +$$$$ diff --git a/modules/io/tests/testfiles/sdf/multiple.sdf b/modules/io/tests/testfiles/sdf/multiple.sdf new file mode 100644 index 0000000000000000000000000000000000000000..7570f2d4d20c126c4a204d08de85df893c43e03c --- /dev/null +++ b/modules/io/tests/testfiles/sdf/multiple.sdf @@ -0,0 +1,72 @@ +Simple Ligand 1 + + Teststructure + 6 6 0 0 1 0 999 V2000 + 0.0000 0.0000 0.0000 N 0 3 0 0 0 0 + 1.0000 0.0000 0.0000 C 0 0 0 0 0 0 + 0.0000 1.0000 0.0000 O 0 0 0 0 0 0 + 1.0000 1.0000 0.0000 S 0 0 0 0 0 0 + 2.0000 2.0000 0.0000 C 0 0 0 0 0 0 + -1.0000 -1.0000 0.0000 Cl 0 0 0 0 0 0 + 1 2 2 0 0 0 + 1 3 1 0 0 0 + 1 6 1 0 0 0 + 2 4 1 0 0 0 + 3 4 1 0 0 0 + 4 5 3 0 0 0 +M END +$$$$ +Simple Ligand 2 + + Teststructure + 6 6 0 0 1 0 999 V2000 + 0.0000 0.0000 0.0000 N 0 3 0 0 0 0 + 1.0000 0.0000 0.0000 C 0 0 0 0 0 0 + 0.0000 1.0000 0.0000 O 0 0 0 0 0 0 + 1.0000 1.0000 0.0000 S 0 0 0 0 0 0 + 2.0000 2.0000 0.0000 C 0 0 0 0 0 0 + -1.0000 -1.0000 0.0000 Cl 0 0 0 0 0 0 + 1 2 2 0 0 0 + 1 3 1 0 0 0 + 1 6 1 0 0 0 + 2 4 1 0 0 0 + 3 4 1 0 0 0 + 4 5 3 0 0 0 +M END +$$$$ +Simple Ligand 3 + + Teststructure + 6 6 0 0 1 0 999 V2000 + 0.0000 0.0000 0.0000 N 0 3 0 0 0 0 + 1.0000 0.0000 0.0000 C 0 0 0 0 0 0 + 0.0000 1.0000 0.0000 O 0 0 0 0 0 0 + 1.0000 1.0000 0.0000 S 0 0 0 0 0 0 + 2.0000 2.0000 0.0000 C 0 0 0 0 0 0 + -1.0000 -1.0000 0.0000 Cl 0 0 0 0 0 0 + 1 2 2 0 0 0 + 1 3 1 0 0 0 + 1 6 1 0 0 0 + 2 4 1 0 0 0 + 3 4 1 0 0 0 + 4 5 3 0 0 0 +M END +$$$$ +Simple Ligand 4 + + Teststructure + 6 6 0 0 1 0 999 V2000 + 0.0000 0.0000 0.0000 N 0 3 0 0 0 0 + 1.0000 0.0000 0.0000 C 0 0 0 0 0 0 + 0.0000 1.0000 0.0000 O 0 0 0 0 0 0 + 1.0000 1.0000 0.0000 S 0 0 0 0 0 0 + 2.0000 2.0000 0.0000 C 0 0 0 0 0 0 + -1.0000 -1.0000 0.0000 Cl 0 0 0 0 0 0 + 1 2 2 0 0 0 + 1 3 1 0 0 0 + 1 6 1 0 0 0 + 2 4 1 0 0 0 + 3 4 1 0 0 0 + 4 5 3 0 0 0 +M END +$$$$ diff --git a/modules/io/tests/testfiles/sdf/properties.sdf b/modules/io/tests/testfiles/sdf/properties.sdf new file mode 100644 index 0000000000000000000000000000000000000000..95a1b950f17cc69020e01e5e6aa8aaf694400c3e --- /dev/null +++ b/modules/io/tests/testfiles/sdf/properties.sdf @@ -0,0 +1,48 @@ +Simple Ligand 1 + + Teststructure + 6 6 0 0 1 0 999 V2000 + 0.0000 0.0000 0.0000 N 0 3 0 0 0 0 + 1.0000 0.0000 0.0000 C 0 0 0 0 0 0 + 0.0000 1.0000 0.0000 O 0 0 0 0 0 0 + 1.0000 1.0000 0.0000 S 0 0 0 0 0 0 + 2.0000 2.0000 0.0000 C 0 0 0 0 0 0 + -1.0000 -1.0000 0.0000 Cl 0 0 0 0 0 0 + 1 2 2 0 0 0 + 1 3 1 0 0 0 + 1 6 1 0 0 0 + 2 4 1 0 0 0 + 3 4 1 0 0 0 + 4 5 3 0 0 0 +M END +> <prop_one> +1 + +> <prop_two> +-2.2 + +$$$$ +Simple Ligand 2 + + Teststructure + 6 6 0 0 1 0 999 V2000 + 0.0000 0.0000 0.0000 N 0 3 0 0 0 0 + 1.0000 0.0000 0.0000 C 0 0 0 0 0 0 + 0.0000 1.0000 0.0000 O 0 0 0 0 0 0 + 1.0000 1.0000 0.0000 S 0 0 0 0 0 0 + 2.0000 2.0000 0.0000 C 0 0 0 0 0 0 + -1.0000 -1.0000 0.0000 Cl 0 0 0 0 0 0 + 1 2 2 0 0 0 + 1 3 1 0 0 0 + 1 6 1 0 0 0 + 2 4 1 0 0 0 + 3 4 1 0 0 0 + 4 5 3 0 0 0 +M END +> <prop_one> +2 + +> <prop_two> +-4.4 + +$$$$ diff --git a/modules/io/tests/testfiles/sdf/simple.sdf b/modules/io/tests/testfiles/sdf/simple.sdf new file mode 100644 index 0000000000000000000000000000000000000000..beeb1acdd6f5423f6886907a79304d04152230d4 --- /dev/null +++ b/modules/io/tests/testfiles/sdf/simple.sdf @@ -0,0 +1,18 @@ +Simple Ligand + + Teststructure + 6 6 0 0 1 0 999 V2000 + 0.0000 0.0000 0.0000 N 0 3 0 0 0 0 + 1.0000 0.0000 0.0000 C 0 0 0 0 0 0 + 0.0000 1.0000 0.0000 O 0 0 0 0 0 0 + 1.0000 1.0000 0.0000 S 0 0 0 0 0 0 + 2.0000 2.0000 0.0000 C 0 0 0 0 0 0 + -1.0000 -1.0000 0.0000 Cl 0 0 0 0 0 0 + 1 2 2 0 0 0 + 1 3 1 0 0 0 + 1 6 1 0 0 0 + 2 4 1 0 0 0 + 3 4 1 0 0 0 + 4 5 3 0 0 0 +M END +$$$$ diff --git a/modules/io/tests/testfiles/sdf/wrong_atomcount.sdf b/modules/io/tests/testfiles/sdf/wrong_atomcount.sdf new file mode 100644 index 0000000000000000000000000000000000000000..ff9049fac2234cd7b10d1a80c9a2bad556651093 --- /dev/null +++ b/modules/io/tests/testfiles/sdf/wrong_atomcount.sdf @@ -0,0 +1,18 @@ +Simple Ligand + + Teststructure + i 6 0 0 1 0 999 V2000 + 0.0000 0.0000 0.0000 N 0 3 0 0 0 0 + 1.0000 0.0000 0.0000 C 0 0 0 0 0 0 + 0.0000 1.0000 0.0000 O 0 0 0 0 0 0 + 1.0000 1.0000 0.0000 S 0 0 0 0 0 0 + 2.0000 2.0000 0.0000 C 0 0 0 0 0 0 + -1.0000 -1.0000 0.0000 Cl 0 0 0 0 0 0 + 1 2 2 0 0 0 + 1 3 1 0 0 0 + 1 6 1 0 0 0 + 2 4 1 0 0 0 + 3 4 1 0 0 0 + 4 5 3 0 0 0 +M END +$$$$ diff --git a/modules/io/tests/testfiles/sdf/wrong_atomlinelength.sdf b/modules/io/tests/testfiles/sdf/wrong_atomlinelength.sdf new file mode 100644 index 0000000000000000000000000000000000000000..42f30f1a5949180bb2e388eb0793f15e045c19cc --- /dev/null +++ b/modules/io/tests/testfiles/sdf/wrong_atomlinelength.sdf @@ -0,0 +1,18 @@ +Simple Ligand + + Teststructure + 6 6 0 0 1 0 999 V2000 + 0.0000 0.0000 0.0000 N 0 3 0 0 0 0 + 1.0000 0.0000 0.0000 C 0 0 + 0.0000 1.0000 0.0000 O 0 0 0 0 0 0 + 1.0000 1.0000 0.0000 S 0 0 0 0 0 0 + 2.0000 2.0000 0.0000 C 0 0 0 0 0 0 + -1.0000 -1.0000 0.0000 Cl 0 0 0 0 0 0 + 1 2 2 0 0 0 + 1 3 1 0 0 0 + 1 6 1 0 0 0 + 2 4 1 0 0 0 + 3 4 1 0 0 0 + 4 5 3 0 0 0 +M END +$$$$ diff --git a/modules/io/tests/testfiles/sdf/wrong_atompos.sdf b/modules/io/tests/testfiles/sdf/wrong_atompos.sdf new file mode 100644 index 0000000000000000000000000000000000000000..50d5268a006d1e78dbbb05a4b2d1bba6706065b4 --- /dev/null +++ b/modules/io/tests/testfiles/sdf/wrong_atompos.sdf @@ -0,0 +1,18 @@ +Simple Ligand + + Teststructure + 6 6 0 0 1 0 999 V2000 + 0.0000 0.0000 0.0000 N 0 3 0 0 0 0 + 1.0000 0.0000 0.0000 C 0 0 0 0 0 0 +0.0000 1.0000 0.0000 O 0 0 0 0 0 0 + 1.0000 1.0000 0.0000 S 0 0 0 0 0 0 + 2.0000 2.0000 0.0000 C 0 0 0 0 0 0 + -1.0000 -1.0000 0.0000 Cl 0 0 0 0 0 0 + 1 2 2 0 0 0 + 1 3 1 0 0 0 + 1 6 1 0 0 0 + 2 4 1 0 0 0 + 3 4 1 0 0 0 + 4 5 3 0 0 0 +M END +$$$$ diff --git a/modules/io/tests/testfiles/sdf/wrong_bondatomnumber.sdf b/modules/io/tests/testfiles/sdf/wrong_bondatomnumber.sdf new file mode 100644 index 0000000000000000000000000000000000000000..590827c4d80a9b4aef6922185e81d753c03fb9c6 --- /dev/null +++ b/modules/io/tests/testfiles/sdf/wrong_bondatomnumber.sdf @@ -0,0 +1,18 @@ +Simple Ligand + + Teststructure + 6 6 0 0 1 0 999 V2000 + 0.0000 0.0000 0.0000 N 0 3 0 0 0 0 + 1.0000 0.0000 0.0000 C 0 0 0 0 0 0 + 0.0000 1.0000 0.0000 O 0 0 0 0 0 0 + 1.0000 1.0000 0.0000 S 0 0 0 0 0 0 + 2.0000 2.0000 0.0000 C 0 0 0 0 0 0 + -1.0000 -1.0000 0.0000 Cl 0 0 0 0 0 0 + 1 2 2 0 0 0 + 1 3 1 0 0 0 + 1 8 1 0 0 0 + 2 4 1 0 0 0 + 3 4 1 0 0 0 + 4 5 3 0 0 0 +M END +$$$$ diff --git a/modules/io/tests/testfiles/sdf/wrong_bondcount.sdf b/modules/io/tests/testfiles/sdf/wrong_bondcount.sdf new file mode 100644 index 0000000000000000000000000000000000000000..3d6194d1bf8ecee440f05b3d5d0edb58aa097c16 --- /dev/null +++ b/modules/io/tests/testfiles/sdf/wrong_bondcount.sdf @@ -0,0 +1,18 @@ +Simple Ligand + + Teststructure + 6 i 0 0 1 0 999 V2000 + 0.0000 0.0000 0.0000 N 0 3 0 0 0 0 + 1.0000 0.0000 0.0000 C 0 0 0 0 0 0 + 0.0000 1.0000 0.0000 O 0 0 0 0 0 0 + 1.0000 1.0000 0.0000 S 0 0 0 0 0 0 + 2.0000 2.0000 0.0000 C 0 0 0 0 0 0 + -1.0000 -1.0000 0.0000 Cl 0 0 0 0 0 0 + 1 2 2 0 0 0 + 1 3 1 0 0 0 + 1 6 1 0 0 0 + 2 4 1 0 0 0 + 3 4 1 0 0 0 + 4 5 3 0 0 0 +M END +$$$$ diff --git a/modules/io/tests/testfiles/sdf/wrong_bondlinelength.sdf b/modules/io/tests/testfiles/sdf/wrong_bondlinelength.sdf new file mode 100644 index 0000000000000000000000000000000000000000..5be46a3936a635f503d5ec22bf7ccfb456b79922 --- /dev/null +++ b/modules/io/tests/testfiles/sdf/wrong_bondlinelength.sdf @@ -0,0 +1,18 @@ +Simple Ligand + + Teststructure + 6 6 0 0 1 0 999 V2000 + 0.0000 0.0000 0.0000 N 0 3 0 0 0 0 + 1.0000 0.0000 0.0000 C 0 0 0 0 0 0 + 0.0000 1.0000 0.0000 O 0 0 0 0 0 0 + 1.0000 1.0000 0.0000 S 0 0 0 0 0 0 + 2.0000 2.0000 0.0000 C 0 0 0 0 0 0 + -1.0000 -1.0000 0.0000 Cl 0 0 0 0 0 0 + 1 2 2 + 1 3 1 0 0 0 + 1 6 1 0 0 0 + 2 4 1 0 0 0 + 3 4 1 0 0 0 + 4 5 3 0 0 0 +M END +$$$$ diff --git a/modules/io/tests/testfiles/sdf/wrong_bondtype.sdf b/modules/io/tests/testfiles/sdf/wrong_bondtype.sdf new file mode 100644 index 0000000000000000000000000000000000000000..432c10464577c35eedf0184ac91af190f040917a --- /dev/null +++ b/modules/io/tests/testfiles/sdf/wrong_bondtype.sdf @@ -0,0 +1,18 @@ +Simple Ligand + + Teststructure + 6 6 0 0 1 0 999 V2000 + 0.0000 0.0000 0.0000 N 0 3 0 0 0 0 + 1.0000 0.0000 0.0000 C 0 0 0 0 0 0 + 0.0000 1.0000 0.0000 O 0 0 0 0 0 0 + 1.0000 1.0000 0.0000 S 0 0 0 0 0 0 + 2.0000 2.0000 0.0000 C 0 0 0 0 0 0 + -1.0000 -1.0000 0.0000 Cl 0 0 0 0 0 0 + 1 2 2 0 0 0 + 1 3 1 0 0 0 + 1 6 -1 0 0 0 + 2 4 1 0 0 0 + 3 4 1 0 0 0 + 4 5 3 0 0 0 +M END +$$$$ diff --git a/modules/io/tests/testfiles/sdf/wrong_charge.sdf b/modules/io/tests/testfiles/sdf/wrong_charge.sdf new file mode 100644 index 0000000000000000000000000000000000000000..01dba009edefaa87b3d76154adb0274287e9c78b --- /dev/null +++ b/modules/io/tests/testfiles/sdf/wrong_charge.sdf @@ -0,0 +1,18 @@ +Simple Ligand + + Teststructure + 6 6 0 0 1 0 999 V2000 + 0.0000 0.0000 0.0000 N 0 3 0 0 0 0 + 1.0000 0.0000 0.0000 C 0 0 0 0 0 0 + 0.0000 1.0000 0.0000 O 0 0 0 0 0 0 + 1.0000 1.0000 0.0000 S 0 i 0 0 0 0 + 2.0000 2.0000 0.0000 C 0 0 0 0 0 0 + -1.0000 -1.0000 0.0000 Cl 0 0 0 0 0 0 + 1 2 2 0 0 0 + 1 3 1 0 0 0 + 1 6 1 0 0 0 + 2 4 1 0 0 0 + 3 4 1 0 0 0 + 4 5 3 0 0 0 +M END +$$$$ diff --git a/modules/io/tests/testfiles/sdf/wrong_dataheader.sdf b/modules/io/tests/testfiles/sdf/wrong_dataheader.sdf new file mode 100644 index 0000000000000000000000000000000000000000..b895448e62e8fdde894bdbd773288417434b0221 --- /dev/null +++ b/modules/io/tests/testfiles/sdf/wrong_dataheader.sdf @@ -0,0 +1,48 @@ +Simple Ligand 1 + + Teststructure + 6 6 0 0 1 0 999 V2000 + 0.0000 0.0000 0.0000 N 0 3 0 0 0 0 + 1.0000 0.0000 0.0000 C 0 0 0 0 0 0 + 0.0000 1.0000 0.0000 O 0 0 0 0 0 0 + 1.0000 1.0000 0.0000 S 0 0 0 0 0 0 + 2.0000 2.0000 0.0000 C 0 0 0 0 0 0 + -1.0000 -1.0000 0.0000 Cl 0 0 0 0 0 0 + 1 2 2 0 0 0 + 1 3 1 0 0 0 + 1 6 1 0 0 0 + 2 4 1 0 0 0 + 3 4 1 0 0 0 + 4 5 3 0 0 0 +M END +> prop_one> +1 + +> <prop_two> +-2 + +$$$$ +Simple Ligand 2 + + Teststructure + 6 6 0 0 1 0 999 V2000 + 0.0000 0.0000 0.0000 N 0 3 0 0 0 0 + 1.0000 0.0000 0.0000 C 0 0 0 0 0 0 + 0.0000 1.0000 0.0000 O 0 0 0 0 0 0 + 1.0000 1.0000 0.0000 S 0 0 0 0 0 0 + 2.0000 2.0000 0.0000 C 0 0 0 0 0 0 + -1.0000 -1.0000 0.0000 Cl 0 0 0 0 0 0 + 1 2 2 0 0 0 + 1 3 1 0 0 0 + 1 6 1 0 0 0 + 2 4 1 0 0 0 + 3 4 1 0 0 0 + 4 5 3 0 0 0 +M END +> <prop_one> +2 + +> <prop_two> +-4 + +$$$$ diff --git a/modules/mol/alg/pymod/CMakeLists.txt b/modules/mol/alg/pymod/CMakeLists.txt index 6c68c3fc4263a7f8cd634c633bb425337cfa68f8..30fae2eb199a4ff4f4c461eefcd5bfc4f00d12c8 100644 --- a/modules/mol/alg/pymod/CMakeLists.txt +++ b/modules/mol/alg/pymod/CMakeLists.txt @@ -7,6 +7,16 @@ set(OST_MOL_ALG_PYMOD_MODULES "__init__.py" views.py ) + +if (ENABLE_IMG) + + set(OST_MOL_ALG_PYMOD_SOURCES + ${OST_MOL_ALG_PYMOD_SOURCES} + export_entity_to_density.cc + ) + +endif() + pymod(NAME mol_alg OUTPUT_DIR ost/mol/alg CPP ${OST_MOL_ALG_PYMOD_SOURCES} PY ${OST_MOL_ALG_PYMOD_MODULES}) diff --git a/modules/mol/alg/pymod/export_entity_to_density.cc b/modules/mol/alg/pymod/export_entity_to_density.cc new file mode 100644 index 0000000000000000000000000000000000000000..bf9ace1fe76265058ddb3400301fca17cc6d1c83 --- /dev/null +++ b/modules/mol/alg/pymod/export_entity_to_density.cc @@ -0,0 +1,49 @@ +//------------------------------------------------------------------------------ +// This file is part of the OpenStructure project <www.openstructure.org> +// +// Copyright (C) 2008-2010 by the OpenStructure authors +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation; either version 3.0 of the License, or (at your option) +// any later version. +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +//------------------------------------------------------------------------------ + +/* + * Author Juergen Haas + */ +#include <boost/python.hpp> +#include <ost/config.hh> + +#if OST_IMG_ENABLED + +#include <ost/mol/alg/entity_to_density.hh> + +using namespace boost::python; +using namespace ost; +using namespace ost::mol::alg; + +//"thin wrappers" for default parameters +BOOST_PYTHON_FUNCTION_OVERLOADS(etd_rosetta, EntityToDensityRosetta, 4, 6) +BOOST_PYTHON_FUNCTION_OVERLOADS(etd_scattering, EntityToDensityScattering, 4, 6) + +void export_entity_to_density() +{ + def("EntityToDensityRosetta",EntityToDensityRosetta,etd_rosetta()); + def("EntityToDensityScattering",EntityToDensityScattering,etd_scattering()); + + enum_<DensityType>("DensityType") + .value("HIGH_RESOLUTION", HIGH_RESOLUTION) + .value("LOW_RESOLUTION", LOW_RESOLUTION) + .export_values() + ; +} +#endif diff --git a/modules/mol/alg/pymod/wrap_mol_alg.cc b/modules/mol/alg/pymod/wrap_mol_alg.cc index 1670b122e20cf6053bef0866d0dbb794ecb65315..ce0be429c6afb0afd5b6b55b2252cc79d446dbbd 100644 --- a/modules/mol/alg/pymod/wrap_mol_alg.cc +++ b/modules/mol/alg/pymod/wrap_mol_alg.cc @@ -21,10 +21,19 @@ * Author Juergen Haas */ #include <boost/python.hpp> +#include <ost/config.hh> using namespace boost::python; void export_svdSuperPose(); + +#if OST_IMG_ENABLED +void export_entity_to_density(); +#endif + BOOST_PYTHON_MODULE(_mol_alg) { export_svdSuperPose(); + #if OST_IMG_ENABLED + export_entity_to_density(); + #endif } diff --git a/modules/mol/alg/src/CMakeLists.txt b/modules/mol/alg/src/CMakeLists.txt index 0eff2e75f86b2c1b0f911ae85e938d21d70f1fbd..242eea3d8f3a4c80f29909b3ecad313df10753f7 100644 --- a/modules/mol/alg/src/CMakeLists.txt +++ b/modules/mol/alg/src/CMakeLists.txt @@ -9,8 +9,27 @@ set(OST_MOL_ALG_SOURCES sec_structure_segments.cc ) +set(MOL_ALG_DEPS mol) + +if (ENABLE_IMG) + set(OST_MOL_ALG_HEADERS + ${OST_MOL_ALG_HEADERS} + entity_to_density.hh + ) + + set(OST_MOL_ALG_SOURCES + ${OST_MOL_ALG_SOURCES} + entity_to_density.cc + ) + + set(MOL_ALG_DEPS ${MOL_ALG_DEPS} img img_alg) +endif() + module(NAME mol_alg SOURCES ${OST_MOL_ALG_SOURCES} HEADERS ${OST_MOL_ALG_HEADERS} HEADER_OUTPUT_DIR ost/mol/alg - DEPENDS_ON mol) + DEPENDS_ON ${MOL_ALG_DEPS}) +copy_if_different("." "${STAGE_DIR}/share/openstructure" + "atom_scattering_properties.txt" "ATOM_SCATTERING_PROPS" + "ost_mol_alg") diff --git a/modules/mol/alg/src/atom_scattering_properties.txt b/modules/mol/alg/src/atom_scattering_properties.txt new file mode 100644 index 0000000000000000000000000000000000000000..107a71bdfe10092cc10075d82318c5b34ca6a0c0 --- /dev/null +++ b/modules/mol/alg/src/atom_scattering_properties.txt @@ -0,0 +1,59 @@ +// SCATTERING PROPERTIES OF ATOMS +// (used by the entity_to_density_function of OST/OPENSTRUCTURE) +// Columns from left to right: 1) Element Symbol 2) Atomic Weight 3) c parameter used to compute scattering factors 4-7) a1-a4 parameters 8-11) b1-b4 parameters. +// Sources: parameters for scattering factors: it.iucr.org/ International tables for crystallography. First online edition (2006), Vol.C,Ch 6.1, pp. 554-595 +// Atomic Weights: www.chem.qmul.ac.uk/iupac/AtWt/ based on 2005 table published in Pure Appl. Chem., 78, 2051-2066 (2006) with 2007 changes +Al 26.982 1.115100 6.420200 1.900200 1.593600 1.964600 3.038700 0.742600 31.547199 85.088600 +As 74.922 2.531000 16.672300 6.070100 3.431300 4.277900 2.634500 0.264700 12.947900 47.797199 +At 210.000 13.710800 35.316299 19.021099 9.498870 7.425180 0.685870 3.974580 11.382400 45.471500 +Au 196.967 12.065800 16.881901 18.591299 25.558201 5.860000 0.461100 8.621600 1.482600 36.395599 +B 10.812 -0.193200 2.054500 1.332600 1.097900 0.706800 23.218500 1.021000 60.349800 0.140300 +Be 9.012 0.038500 1.591900 1.127800 0.539100 0.702900 43.642700 1.862300 103.483002 0.542000 +Br 79.904 2.955700 17.178900 5.235800 5.637700 3.985100 2.172300 16.579599 0.260900 41.432800 +C 12.011 0.215600 2.310000 1.020000 1.588600 0.865000 20.843899 10.207500 0.568700 51.651199 +Ca 40.078 1.375100 8.626600 7.387300 1.589900 1.021100 10.442100 0.659900 85.748398 178.436996 +Cd 112.412 5.069400 19.221399 17.644400 4.461000 1.602900 0.594600 6.908900 24.700800 87.482498 +Cl 35.453 -9.557400 11.460400 7.196400 6.255600 1.645500 0.010400 1.166200 18.519400 47.778400 +Co 58.933 1.011800 12.284100 7.340900 4.003400 2.348800 4.279100 0.278400 13.535900 71.169197 +Cr 51.996 1.183200 10.640600 7.353700 3.324000 1.492200 6.103800 0.392000 20.262600 98.739899 +Cu 63.546 1.191000 13.337999 7.167600 5.615800 1.673500 3.582800 0.247000 11.396600 64.812599 +F 18.998 0.277600 3.539200 2.641200 1.517000 1.024300 10.282499 4.294400 0.261500 26.147600 +Fe 55.845 1.036900 11.769500 7.357300 3.522200 2.304500 4.761100 0.307200 15.353500 76.880501 +Ga 69.723 1.718900 15.235400 6.700600 4.359100 2.962300 3.066900 0.241200 10.780500 61.413498 +Gd 157.253 2.419600 25.070900 19.079800 13.851800 3.545450 2.253410 0.181951 12.933100 101.397995 +Ge 72.641 2.131300 16.081600 6.374700 3.706800 3.683000 2.850900 0.251600 11.446800 54.762501 +Hf 178.492 8.581540 29.143999 15.172600 14.758600 4.300130 1.832620 9.599899 0.275116 72.028999 +Hg 200.592 12.608900 20.680901 19.041700 21.657499 5.967600 0.545000 8.448400 1.572900 38.324600 +I 126.904 4.071200 20.147200 18.994900 7.513800 2.273500 4.347000 0.381400 27.765999 66.877602 +Ir 192.217 11.472200 27.304899 16.729599 15.611500 5.833770 1.592790 8.865530 0.417916 45.001099 +K 39.098 1.422800 8.218599 7.439800 1.051900 0.865900 12.794900 0.774800 213.186996 41.684097 +Li 6.941 0.037700 1.128200 0.750800 0.617500 0.465300 3.954600 1.052400 85.390503 168.261002 +Mg 24.305 0.858400 5.420400 2.173500 1.226900 2.307300 2.827500 79.261101 0.380800 7.193700 +Mn 54.938 1.089600 11.281900 7.357300 3.019300 2.244100 5.340900 0.343200 17.867399 83.754303 +Mo 95.962 4.387500 3.702500 17.235600 12.887600 3.742900 0.277200 1.095800 11.004000 61.658401 +N 14.007 11.528999 12.212600 3.132200 2.012500 1.166300 0.005700 9.893300 28.997499 0.582600 +Na 22.990 0.676000 4.762600 3.173600 1.267400 1.112800 3.285000 8.842199 0.313600 129.423996 +Ni 58.693 1.034100 12.837600 7.292000 4.443800 2.380000 3.878500 0.256500 12.176300 66.342102 +O 15.999 0.250800 3.048500 2.286800 1.546300 0.867000 13.277100 5.701100 0.323900 32.908897 +Os 190.233 11.000500 28.189400 16.154999 14.930500 5.675890 1.629030 8.979480 0.382661 48.164700 +P 30.974 1.114900 6.434500 4.179100 1.780000 1.490800 1.906700 27.157000 0.526000 68.164497 +Pb 207.210 13.411800 31.061699 13.063700 18.441999 5.969600 0.690200 2.357600 8.618000 47.257900 +Pd 106.421 5.265930 19.331900 15.501699 5.295370 0.605844 0.698655 7.989290 25.205200 76.898598 +Pt 195.085 11.688300 27.005899 17.763901 15.713100 5.783700 1.512930 8.811740 0.424593 38.610298 +Re 186.207 10.472000 28.762100 15.718900 14.556400 5.441740 1.671910 9.092270 0.350500 52.086098 +Rh 102.905 5.328000 19.295700 14.350100 4.734250 1.289180 0.751536 8.217580 25.874901 98.606201 +Ru 101.072 5.378740 19.267399 12.918200 4.863370 1.567560 0.808520 8.434669 24.799700 94.292801 +S 32.066 0.866900 6.905300 5.203400 1.437900 1.586300 1.467900 22.215099 0.253600 56.172001 +Sb 121.760 4.590900 19.641800 19.045500 5.037100 2.682700 5.303400 0.460700 27.907400 75.282501 +Se 78.963 2.840900 17.000599 5.819600 3.973100 4.354300 2.409800 0.272600 15.237200 43.816299 +Si 28.086 1.140700 6.291500 3.035300 1.989100 1.541000 2.438600 32.333698 0.678500 81.693695 +Sn 118.711 4.782100 19.188900 19.100500 4.458500 2.466300 5.830300 0.503100 26.890900 83.957100 +Ta 180.948 9.243540 29.202400 15.229300 14.513500 4.764920 1.773330 9.370460 0.295977 63.364399 +Te 127.603 4.352000 19.964399 19.013800 6.144870 2.523900 4.817420 0.420885 28.528400 70.840302 +U 238.029 13.396600 36.022800 23.412800 14.949100 4.188000 0.529300 3.325300 16.092699 100.612999 +V 50.942 1.219900 10.297100 7.351100 2.070300 2.057100 6.865700 0.438500 26.893799 102.477997 +W 183.841 9.887500 29.081800 15.430000 14.432700 5.119820 1.720290 9.225900 0.321703 57.056000 +Y 88.906 1.912130 17.775999 10.294600 5.726290 3.265880 1.402900 12.800600 0.125599 104.353996 +Zn 65.382 1.304100 14.074300 7.031800 5.162500 2.410000 3.265500 0.233300 10.316299 58.709702 +Zr 91.2240 2.069290 17.876499 10.948000 5.417320 3.657210 1.276180 11.916000 0.117622 87.662697 + diff --git a/modules/mol/alg/src/entity_to_density.cc b/modules/mol/alg/src/entity_to_density.cc new file mode 100644 index 0000000000000000000000000000000000000000..269f23add94f340c0b3f4eb40184b9feadc81bf7 --- /dev/null +++ b/modules/mol/alg/src/entity_to_density.cc @@ -0,0 +1,442 @@ +#include <sstream> +#include <cmath> + +#include <boost/filesystem/fstream.hpp> +#include <boost/filesystem/convenience.hpp> +#include <boost/algorithm/string.hpp> + +#include <ost/log.hh> +#include <ost/platform.hh> +#include <ost/img/alg/dft.hh> +#include <ost/mol/mol.hh> + +#include "entity_to_density.hh" + +namespace ost { namespace mol { namespace alg { + +namespace detail { + +struct AtomScatteringProps { + String element; + Real atomic_weight; + Real c; + Real a1; + Real a2; + Real a3; + Real a4; + Real b1; + Real b2; + Real b3; + Real b4; +}; + +typedef std::vector<AtomScatteringProps> AtomScatteringPropsTable; + +void FillAtomScatteringPropsTable(AtomScatteringPropsTable& table) +{ + AtomScatteringProps atom_props; + + String ost_root=GetSharedDataPath(); + String filename = "/atom_scattering_properties.txt"; + String fullpath = ost_root+filename; + boost::filesystem::path loc(fullpath); + boost::filesystem::ifstream infile(loc); + if (!infile) { + String msg; + std::stringstream msgstr(msg); + msgstr << "Couldn't find " << fullpath << std::endl; + throw ost::Error(msg); + } + String line; + std::getline(infile, line); + std::getline(infile, line); + std::getline(infile, line); + std::getline(infile, line); + std::getline(infile, line); + while (std::getline(infile, line)) + { + std::stringstream line_stream(line); + line_stream >> atom_props.element + >> atom_props.atomic_weight + >> atom_props.c + >> atom_props.a1 + >> atom_props.a2 + >> atom_props.a3 + >> atom_props.a4 + >> atom_props.b1 + >> atom_props.b2 + >> atom_props.b3 + >> atom_props.b4; + table.push_back(atom_props); + } +}; + + +Real ScatteringFactor (Real frequency, const AtomScatteringProps& props, + Real source_wavelength) +{ + Real scattering_factor = + props.a1*exp(-props.b1*frequency*frequency) + + props.a2*exp(-props.b2*frequency*frequency) + + props.a3*exp(-props.b3*frequency*frequency) + + props.a4*exp(-props.b4*frequency*frequency) + + props.c; + + return scattering_factor; +} + + +class EntityToDensityHelperBase +{ + +public: + + EntityToDensityHelperBase (const ost::mol::EntityView entity_view, + Real falloff_start, + Real falloff_end, + Real source_wavelength, + geom::Vec3 map_start, + geom::Vec3 map_end + ): + entity_view_(entity_view), + falloff_start_frequency_(1.0/falloff_start), + falloff_end_frequency_(1.0/falloff_end), + source_wavelength_(source_wavelength), + map_start_(map_start),map_end_(map_end) + { + if (scattering_props_table_loaded_ == false) + { + FillAtomScatteringPropsTable(scatt_props_table_); + scattering_props_table_loaded_ = true; + } + } + + void VisitState(img::ComplexHalfFrequencyImageState& is) const + { + + geom::Vec3 frequency_sampling = + is.GetSampling().GetFrequencySampling(); + + Real minus_2_pi = -2.0*M_PI; + + uint x_limit = ceil(falloff_end_frequency_ / frequency_sampling[0]); + uint y_limit = ceil(falloff_end_frequency_ / frequency_sampling[1]); + uint z_limit = ceil(falloff_end_frequency_ / frequency_sampling[2]); + img::Extent reduced_extent = img::Extent + (img::Point(-x_limit,-y_limit,0), + img::Point(x_limit,y_limit,z_limit)); + + mol::AtomViewIter iterator_end = entity_view_.AtomsEnd(); + for (mol::AtomViewIter iterator = entity_view_.AtomsBegin(); + iterator!=iterator_end; ++iterator) + { + AtomScatteringPropsTable::iterator table_iter = + scatt_props_table_.begin(); + bool found = false; + while (found != true && table_iter!=scatt_props_table_.end()) + { + if ( (*table_iter).element == (*iterator).GetAtomProps().element) + { + geom::Vec3 coord = (*iterator).GetPos(); + + if (coord[0] >= map_start_[0] && + coord[0] <= map_end_[0] && + coord[1] >= map_start_[1] && + coord[1] <= map_end_[1] && + coord[2] >= map_start_[2] && + coord[2] <= map_end_[2]) + { + + // This part of the code assumes that the three axes + // of the map are at right angles and the origin at 0,0,0. + // Eventually, when maps and images will be merged, + // it will substituted by the map's xyz2uvw method + + geom::Vec3 adjusted_coord = coord-map_start_; + + for (img::ExtentIterator mp_it(reduced_extent); + !mp_it.AtEnd();++mp_it) + { + img::Point mp_it_point = img::Point(mp_it); + + geom::Vec3 frequency_sampling = + is.GetSampling().GetFrequencySampling(); + + geom::Vec3 mp_it_vec = geom::Vec3( + (mp_it_point[0]*frequency_sampling[0]), + (mp_it_point[1]*frequency_sampling[1]), + (mp_it_point[2]*frequency_sampling[2]) + ); + + Real frequency = Length(mp_it_vec); + + Real sigma = (falloff_end_frequency_ - + falloff_start_frequency_)/3.0; + + if (frequency <= falloff_end_frequency_) + { + Real falloff_term = 1.0; + if (sigma!=0 && frequency >= falloff_start_frequency_) + { + falloff_term=exp(-(frequency-falloff_start_frequency_)* + (frequency-falloff_start_frequency_)/ + (2.0*sigma*sigma)); + } + AtomScatteringProps scatt_props = (*table_iter); + Real scatt_fact = ScatteringFactor(frequency, + scatt_props, + source_wavelength_); + + Real amp_term = scatt_fact*falloff_term; + Real exp = minus_2_pi * geom::Dot(mp_it_vec,adjusted_coord); + Real real = amp_term *std::cos(exp); + Real imag = amp_term *std::sin(exp); + is.Value(mp_it) = is.Value(mp_it)+Complex(real,imag); + + } + } + } + } + ++table_iter; + } + } + } + + template <typename T, class D> + void VisitState(img::ImageStateImpl<T,D>& is) const + { + assert(false); + } + + static String GetAlgorithmName() {return "EntityToDensityHelper"; } + +private: + + ost::mol::alg::DensityType density_type_; + Real limit_; + ost::mol::EntityView entity_view_; + Real falloff_start_frequency_; + Real falloff_end_frequency_; + static AtomScatteringPropsTable scatt_props_table_; + static bool scattering_props_table_loaded_; + Real source_wavelength_; + geom::Vec3 map_start_; + geom::Vec3 map_end_; + +}; + +AtomScatteringPropsTable EntityToDensityHelperBase::scatt_props_table_ = + AtomScatteringPropsTable(); +bool EntityToDensityHelperBase::scattering_props_table_loaded_ = false; + +typedef img::ImageStateConstModIPAlgorithm<EntityToDensityHelperBase> + EntityToDensityHelper; + + + +class EntityToDensityRosettaHelperBase +{ + +public: + + EntityToDensityRosettaHelperBase (const ost::mol::EntityView entity_view, + const ost::mol::alg::DensityType& density_type, + Real resolution): + density_type_(density_type), entity_view_(entity_view), + resolution_(resolution) + { + if (scattering_props_table_loaded_ == false) + { + FillAtomScatteringPropsTable(scatt_props_table_); + scattering_props_table_loaded_ = true; + } + } + + void VisitState(img::RealSpatialImageState& is) const + { + geom::Vec3 map_start=is.IndexToCoord(is.GetExtent().GetStart()); + geom::Vec3 map_end=is.IndexToCoord(is.GetExtent().GetEnd()); + mol::EntityView effective_entity_view=entity_view_; + Real k,C; + + if (density_type_ == HIGH_RESOLUTION) + { + k = (M_PI*M_PI)/(resolution_*resolution_); + C = sqrt((M_PI*M_PI*M_PI)/(k*k*k)); + effective_entity_view = entity_view_; + + } else { // ROSETTA LOW RESOLUTION + + k = (M_PI*M_PI)/((2.4+0.8*resolution_)*(2.4+0.8*resolution_)); + C = sqrt((M_PI*M_PI*M_PI)/(k*k*k)); + + effective_entity_view = entity_view_.Select("aname=CA and peptide=true"); + } + + Real sigma = sqrt(1.0/(2.0*k)); + Real four_sigma_squared = 16.0*sigma*sigma; + Real four_sigma = 4.0*sigma; + + geom::Vec3 sampling = is.GetSampling().GetPixelSampling(); + img::Extent is_extent = is.GetExtent(); + + mol::AtomViewIter iterator_end = effective_entity_view.AtomsEnd(); + for (mol::AtomViewIter iterator = effective_entity_view.AtomsBegin(); + iterator!=iterator_end; ++iterator) { + AtomScatteringPropsTable::iterator table_iter = + scatt_props_table_.begin(); + bool found = false; + while (found != true && table_iter!=scatt_props_table_.end()) { + if ((*table_iter).element == (*iterator).GetAtomProps().element) { + found = true; + Real a = (*table_iter).atomic_weight; + geom::Vec3 coord = (*iterator).GetPos(); + if (coord[0] >= map_start[0] && + coord[0] <= map_end[0] && + coord[1] >= map_start[1] && + coord[1] <= map_end[1] && + coord[2] >= map_start[2] && + coord[2] <= map_end[2]) + { + + geom::Vec3 adjusted_coord = coord-map_start; + geom::Vec3 pixel_coord=is.CoordToIndex(coord); + img::Point rounded_pixel_coord(round(pixel_coord[0]), + round(pixel_coord[1]), + round(pixel_coord[2])); + + uint x_limit = ceil(2.0*four_sigma/sampling[0])+1; + uint y_limit = ceil(2.0*four_sigma/sampling[1])+1; + uint z_limit = ceil(2.0*four_sigma/sampling[2])+1; + + img::Extent reduced_extent = img::Extent + (img::Size(x_limit,y_limit,z_limit), + rounded_pixel_coord); + + img::Extent iteration_extent= + img::Overlap(is_extent,reduced_extent); + + for (img::ExtentIterator mp_it(iteration_extent); + !mp_it.AtEnd();++mp_it) + { + + img::Point mp_it_point = img::Point(mp_it); + + geom::Vec3 mp_it_vec = geom::Vec3( + (mp_it_point[0]*sampling[0]), + (mp_it_point[1]*sampling[1]), + (mp_it_point[2]*sampling[2]) + ); + + Real distance_squared = Length2(mp_it_vec-adjusted_coord); + + if (distance_squared <= four_sigma_squared) + { + Real exp_term = exp(-k*distance_squared); + Real value = C * a * exp_term; + is.Value(mp_it_point) = is.Value(mp_it_point) + value; + } + } + } + } + ++table_iter; + } + } + } + + template <typename T, class D> + void VisitState(img::ImageStateImpl<T,D>& is) const + { + assert(false); + } + + static String GetAlgorithmName() { return "EntityToDensityRosettaHelper"; } + +private: + + ost::mol::alg::DensityType density_type_; + ost::mol::EntityView entity_view_; + Real resolution_; + static AtomScatteringPropsTable scatt_props_table_; + static bool scattering_props_table_loaded_; +}; + +AtomScatteringPropsTable EntityToDensityRosettaHelperBase::scatt_props_table_ = + AtomScatteringPropsTable(); +bool EntityToDensityRosettaHelperBase::scattering_props_table_loaded_ = false; + +typedef img::ImageStateConstModIPAlgorithm<EntityToDensityRosettaHelperBase> + EntityToDensityRosettaHelper; + + +} // namespace + +void EntityToDensityScattering(const mol::EntityView& entity_view, + img::MapHandle& map, + Real falloff_start, + Real falloff_end, + bool clear_map_flag, + Real source_wavelength) +{ + if(falloff_start<=0.0) throw std::runtime_error("Invalid falloff start"); + if(falloff_end<=0.0 || falloff_end>falloff_start) + throw std::runtime_error("Invalid falloff end"); + + geom ::Vec3 rs_sampl = map.GetSpatialSampling(); + geom ::Vec3 abs_orig = map.GetAbsoluteOrigin(); + geom::Vec3 map_start = geom::Vec3(abs_orig[0]+map.GetExtent().GetStart()[0]*rs_sampl[0], + abs_orig[1]+map.GetExtent().GetStart()[1]*rs_sampl[1], + abs_orig[2]+map.GetExtent().GetStart()[2]*rs_sampl[2]); + + geom::Vec3 map_end = geom::Vec3(abs_orig[0]+map.GetExtent().GetEnd()[0]*rs_sampl[0], + abs_orig[1]+map.GetExtent().GetEnd()[1]*rs_sampl[1], + abs_orig[2]+map.GetExtent().GetEnd()[2]*rs_sampl[2]); + detail::EntityToDensityHelper e_to_d_helper(entity_view, + falloff_start, + falloff_end, + source_wavelength, map_start,map_end); + if (clear_map_flag==true) { + img::MapHandle mm=img::CreateImage(img::Extent(map.GetSize(), + img::Point(0,0)), + img::COMPLEX,img::HALF_FREQUENCY); + // swap newly created map into place + mm.SetSpatialSampling(map.GetSpatialSampling()); + mm.SetAbsoluteOrigin(map.GetAbsoluteOrigin()); + map.Swap(mm); + } else { + map.ApplyIP(img::alg::DFT()); + } + + map.ApplyIP(e_to_d_helper); + map.ApplyIP(img::alg::DFT()); +} + + +void EntityToDensityRosetta(const mol::EntityView& entity_view, + img::MapHandle& map, + const DensityType& density_type, + Real resolution, + bool clear_map_flag, + Real source_wavelength) + +{ + if(resolution <=0.0) throw std::runtime_error("Invalid resolution"); + if (clear_map_flag==true) { + img::MapHandle mm=img::CreateImage(img::Extent(img::Point(0,0), + map.GetSize())); + // swap newly created map into place + mm.SetSpatialSampling(map.GetSpatialSampling()); + mm.SetAbsoluteOrigin(map.GetAbsoluteOrigin()); + map.Swap(mm); + } + + detail::EntityToDensityRosettaHelper e_to_d_r_helper + (entity_view,density_type, + resolution); + map.ApplyIP(e_to_d_r_helper); +} + + +}}} // ns + + diff --git a/modules/mol/alg/src/entity_to_density.hh b/modules/mol/alg/src/entity_to_density.hh new file mode 100644 index 0000000000000000000000000000000000000000..fc9180006b533ad891bdf3117b37b375a89fa27d --- /dev/null +++ b/modules/mol/alg/src/entity_to_density.hh @@ -0,0 +1,79 @@ +#ifndef OST_ENTITY_TO_DENSITY_HH +#define OST_ENTITY_TO_DENSITY_HH + +#include <ost/mol/entity_view.hh> +#include <ost/img/map.hh> + +#include <ost/mol/alg/module_config.hh> + + +namespace ost { namespace mol { namespace alg { + +/// \brief type of density being created by the EntityToDensity function +enum DensityType +{ + HIGH_RESOLUTION, + LOW_RESOLUTION +}; + +/// \brief create a density representation of an entity in a density map (using electron scattering factors) +/// +/// This functions creates a density representation of the entity provided by +/// the user in a density map, in Fourier space using the correct scattering +/// factors for the elements involved. +/// +/// The user can also choose if the density map should be cleared of its +/// previous content before creating the density representation. +/// +/// The density is generated in Fourier space. In order to +/// avoid artifacts in the final density representation, the function avoids +/// sharp frequency cutoffs by applying a Gaussian falloff. The user must +/// provide the resolutions at which the cutoff should begin and end, as opposed +/// to a single resolution cutoff value. +/// +/// This function will only create a density represenation of the entities +/// (or portion of entities ) that fall within the borders of the map. +/// The user must take care that this condition is verified for all +/// entities for which he wants a representation. +/// +void DLLEXPORT_OST_MOL_ALG EntityToDensityScattering(const mol::EntityView& entity_view, + img::MapHandle& map, + Real falloff_start, + Real falloff_end, + bool clear_map_flag = false, + Real source_wavelength = 1.5418); + +/// \brief create a density representation of an entity in a density map +/// +/// This function creates a density representation of the entity provided by +/// the user in a density map, also provided by the user. The user can choose +/// the type of density of the output map: +/// +/// ROSETTA_HIGH_RESOLUTION gaussian spheres in real space to represent +/// density, one per atom, see Dimaio et al., +/// Refinement of Protein Structures into Low-Resolution +/// Density Maps Using Rosetta. Journal of Molecular +/// Biology (2009) pp. 1-10 +/// ROSETTA_LOW_RESOLUTION guassian spheres in real space to represent +/// density, one per residue. See reference above. Only +/// useful at low resolution +/// +/// The user can also choose if the density map should be cleared of its +/// previous content before creating the density representation. +/// +/// The user must also provide a resolution parameter. +/// +/// This function will only create a density represenation of the entities +/// (or portion of entities ) that fall within the borders of the map. +/// The user must take care that this condition is verified for all +/// entities for which he wants a representation. +/// +void DLLEXPORT_OST_MOL_ALG EntityToDensityRosetta(const mol::EntityView& entity_view, + img::MapHandle& map, + const DensityType& density_type, + Real resolution, + bool clear_map_flag = false, + Real source_wavelength = 1.5418); +}}} // ns + +#endif // OST_ENTITY_TO_DENSITY diff --git a/modules/mol/base/doc/editors.rst b/modules/mol/base/doc/editors.rst index aaed57b35ea03c395926d4cf745c2483c80cf6a7..f224b2e1fd2290db8be073dda9d18fc36bf052db 100644 --- a/modules/mol/base/doc/editors.rst +++ b/modules/mol/base/doc/editors.rst @@ -1,7 +1,7 @@ Editors ================================================================================ -.. currentmodule:: mol +.. currentmodule:: ost.mol The structure, topology and connectivity of entities is edited via editors. This includes operations such as changing atom positions, connecting atoms with bonds @@ -118,7 +118,7 @@ euclidian space. transform. :param atom: must be a valid atom handle - :type atom: :class:`mol.AtomHandle` + :type atom: :class:`ost.mol.AtomHandle` :param pos: The new position :type pos: :class:`geom.Vec3` @@ -129,7 +129,7 @@ euclidian space. the original pos. :param atom: must be a valid atom handle - :type atom: :class:`mol.AtomHandle` + :type atom: :class:`ost.mol.AtomHandle` :param pos: The new untransformed position :type pos: :class:`geom.Vec3` diff --git a/modules/mol/base/doc/entity.rst b/modules/mol/base/doc/entity.rst index 75e5c6fdea49ec877259a013762b3126c82c6e92..1adcd2de76af8d919b0928bc91b01669912a1a59 100644 --- a/modules/mol/base/doc/entity.rst +++ b/modules/mol/base/doc/entity.rst @@ -1,7 +1,7 @@ The Molecular Entity ================================================================================ -.. currentmodule:: mol +.. currentmodule:: ost.mol This document describes the :class:`EntityHandle` and related classes. @@ -10,7 +10,7 @@ This document describes the :class:`EntityHandle` and related classes. Creates a new entity. The created entity is empty, that is, it does not contain any atoms, residues, chains, bonds or torsions. To populate the - entity, create a new editor. + entity, use an :doc:`editors`. :returns: The newly created :class:`EntityHandle` diff --git a/modules/mol/base/doc/mol.rst b/modules/mol/base/doc/mol.rst index e4de24691c513680a2c512e652cb3085301c4d6a..a16b21f541edbec24a14ea8f96c9183adc9cf4f3 100644 --- a/modules/mol/base/doc/mol.rst +++ b/modules/mol/base/doc/mol.rst @@ -1,7 +1,7 @@ -:mod:`mol` -- Molecular structures and surfaces +:mod:`~ost.mol` -- Molecular structures and surfaces ================================================================================ -.. module:: mol +.. module:: ost.mol :synopsis: Contains classes and functions to deal with molecular structures and surfaces diff --git a/modules/mol/base/pymod/CMakeLists.txt b/modules/mol/base/pymod/CMakeLists.txt index 590af690986b9c300a28917bdbc0aea48f6f0cd9..29c336dca643d9bbafac80ad9fb5e3959e6ef48c 100644 --- a/modules/mol/base/pymod/CMakeLists.txt +++ b/modules/mol/base/pymod/CMakeLists.txt @@ -18,6 +18,7 @@ export_query_view_wrapper.cc export_torsion.cc export_visitor.cc wrap_mol.cc +export_entity_property_mapper.cc ) pymod(NAME mol CPP ${OST_BASE_PYMOD_SOURCES} PY __init__.py) diff --git a/modules/mol/base/pymod/export_atom.cc b/modules/mol/base/pymod/export_atom.cc index 83f2adc0648de4b6eaacccadfba7dbf0337d812b..43e7483a79f7984d348bb85d5bd83be58e785325 100644 --- a/modules/mol/base/pymod/export_atom.cc +++ b/modules/mol/base/pymod/export_atom.cc @@ -27,7 +27,7 @@ using namespace ost; using namespace ost::mol; #include <ost/export_helper/generic_property_def.hh> - +#include <ost/export_helper/vector.hh> void export_Atom() { class_<AtomBase> atom_base("AtomBase", no_init); @@ -42,8 +42,6 @@ void export_Atom() .add_property("qualified_name", &AtomBase::GetQualifiedName) .def("IsValid", &AtomBase::IsValid) .def(self_ns::str(self)) - .add_property("hash_code", &AtomBase::GetHashCode) - .def("GetHashCode", &AtomBase::GetHashCode) .def("GetAtomProps", &AtomBase::GetAtomProps, return_value_policy<copy_const_reference>()) .def("SetAtomProps", &AtomBase::SetAtomProps, args("prop")) @@ -86,14 +84,17 @@ void export_Atom() .add_property("handle", &AtomHandle::GetHandle) .add_property("entity", &AtomHandle::GetEntity) .def("GetBondPartners", &AtomHandle::GetBondPartners) + .def("GetHashCode", &AtomHandle::GetHashCode) .def("FindBondToAtom", &AtomHandle::FindBondToAtom, args("other_atom")) .def(self==self) .def(self!=self) .def("__hash__", &AtomHandle::GetHashCode) + .add_property("hash_code", &AtomHandle::GetHashCode) ; class_<AtomHandleList>("AtomHandleList", no_init) .def(vector_indexing_suite<AtomHandleList>()) + .def(ost::VectorAdditions<AtomHandleList>()) ; class_<AtomProp>("AtomProp", init<>()) .def_readwrite("element", &AtomProp::element) diff --git a/modules/mol/base/pymod/export_atom_view.cc b/modules/mol/base/pymod/export_atom_view.cc index af2dd063b8ea7db1f510ec39aca5df7ad7fce705..bdee6609db8e34db9a52d055ebeac7a4547d3ae0 100644 --- a/modules/mol/base/pymod/export_atom_view.cc +++ b/modules/mol/base/pymod/export_atom_view.cc @@ -22,7 +22,7 @@ using namespace boost::python; #include <ost/mol/mol.hh> - +#include <ost/export_helper/vector.hh> using namespace ost; using namespace ost::mol; @@ -43,10 +43,14 @@ void export_AtomView() .def("GetHandle", &AtomView::GetHandle) .def("GetBondCount", &AtomView::GetBondCount) .def("GetBondList", &AtomView::GetBondList) + .def("GetHashCode", &AtomView::GetHashCode) + .def("__hash__", &AtomView::GetHashCode) + .add_property("hash_code", &AtomView::GetHashCode) .def("GetBondPartners", &AtomView::GetBondPartners) ; class_<AtomViewList>("AtomViewList", init<>()) .def(vector_indexing_suite<AtomViewList>()) + .def(ost::VectorAdditions<AtomViewList>()) ; } diff --git a/modules/mol/base/pymod/export_chain.cc b/modules/mol/base/pymod/export_chain.cc index 57e717ebac7e5a63c108eb0568c9815d09a7994e..fe2019d3affbe500583a2873ab17df6f17b3f900 100644 --- a/modules/mol/base/pymod/export_chain.cc +++ b/modules/mol/base/pymod/export_chain.cc @@ -21,7 +21,7 @@ using namespace boost::python; #include <ost/mol/mol.hh> - +#include <ost/export_helper/vector.hh> using namespace ost; using namespace ost::mol; #include <ost/export_helper/generic_property_def.hh> @@ -92,5 +92,6 @@ void export_Chain() class_<ChainHandleList>("ChainHandleList", no_init) .def(vector_indexing_suite<ChainHandleList>()) + .def(ost::VectorAdditions<ChainHandleList>()) ; } diff --git a/modules/mol/base/pymod/export_chain_view.cc b/modules/mol/base/pymod/export_chain_view.cc index 8de0f77d7a3220db2fd8abe95fdab72340108285..fa8446a5057b6140f27b79742b7bc6876ff4fae2 100644 --- a/modules/mol/base/pymod/export_chain_view.cc +++ b/modules/mol/base/pymod/export_chain_view.cc @@ -24,7 +24,7 @@ using namespace boost::python; #include <ost/mol/query.hh> #include <ost/mol/chain_handle.hh> #include <ost/mol/entity_visitor.hh> - +#include <ost/export_helper/vector.hh> using namespace ost; using namespace ost::mol; @@ -58,6 +58,7 @@ void export_ChainView() { class_<ChainViewList>("ChainViewList", no_init) .def(vector_indexing_suite<ChainViewList>()) + .def(ost::VectorAdditions<ChainViewList>()) ; void (ChainView::* apply1)(EntityVisitor&) = &ChainView::Apply; diff --git a/modules/mol/base/pymod/export_entity_property_mapper.cc b/modules/mol/base/pymod/export_entity_property_mapper.cc new file mode 100644 index 0000000000000000000000000000000000000000..fa271bed83a04df8773f8110e773b94e5a7676e1 --- /dev/null +++ b/modules/mol/base/pymod/export_entity_property_mapper.cc @@ -0,0 +1,68 @@ +#include <boost/python.hpp> + +#include <ost/mol/entity_property_mapper.hh> + +using namespace ost; +using namespace ost::mol; +using namespace boost::python; + +namespace { + + +Real (EntityPropertyMapper::*get_ah_a)(const AtomHandle&) const=&EntityPropertyMapper::Get; +Real (EntityPropertyMapper::*get_av_a)(const AtomView&) const=&EntityPropertyMapper::Get; +Real (EntityPropertyMapper::*get_rh_a)(const ResidueHandle&) const=&EntityPropertyMapper::Get; +Real (EntityPropertyMapper::*get_rv_a)(const ResidueView&) const=&EntityPropertyMapper::Get; +Real (EntityPropertyMapper::*get_ch_a)(const ChainHandle&) const=&EntityPropertyMapper::Get; +Real (EntityPropertyMapper::*get_cv_a)(const ChainView&) const=&EntityPropertyMapper::Get; + + +Real (EntityPropertyMapper::*get_ah_b)(const AtomHandle&, Real) const=&EntityPropertyMapper::Get; +Real (EntityPropertyMapper::*get_av_b)(const AtomView&, Real) const=&EntityPropertyMapper::Get; +Real (EntityPropertyMapper::*get_rh_b)(const ResidueHandle&, Real) const=&EntityPropertyMapper::Get; +Real (EntityPropertyMapper::*get_rv_b)(const ResidueView&, Real) const=&EntityPropertyMapper::Get; +Real (EntityPropertyMapper::*get_ch_b)(const ChainHandle&, Real) const=&EntityPropertyMapper::Get; +Real (EntityPropertyMapper::*get_cv_b)(const ChainView&, Real) const=&EntityPropertyMapper::Get; + +EntityPropertyMapper create_epm(const String& prop_name, char level) +{ + switch(level) { + case 'A': + case 'a': + return EntityPropertyMapper(prop_name, Prop::ATOM); + case 'R': + case 'r': + return EntityPropertyMapper(prop_name, Prop::RESIDUE); + case 'C': + case 'c': + return EntityPropertyMapper(prop_name, Prop::CHAIN); + case 'U': + case 'u': + return EntityPropertyMapper(prop_name, Prop::UNSPECIFIED); + default: + throw std::runtime_error(String("unknown property level '")+level+"'"); + } +} + +} + +void export_EntityPropertyMapper() +{ + class_<EntityPropertyMapper>("EntityPropertyMapper", + init<const String&, + Prop::Level>(arg("level")=Prop::UNSPECIFIED)) + .def("__init__", &create_epm) + .def("Get", get_ah_a) + .def("Get", get_av_a) + .def("Get", get_rh_a) + .def("Get", get_rv_a) + .def("Get", get_ch_a) + .def("Get", get_cv_a) + .def("Get", get_ah_b) + .def("Get", get_av_b) + .def("Get", get_rh_b) + .def("Get", get_rv_b) + .def("Get", get_ch_b) + .def("Get", get_cv_b) + ; +} diff --git a/modules/mol/base/pymod/export_residue.cc b/modules/mol/base/pymod/export_residue.cc index 905c6b5155cf42c0bd1fb187296e9e0f799351e5..0c28df65249210b61a1546f6895f3c343f393f7b 100644 --- a/modules/mol/base/pymod/export_residue.cc +++ b/modules/mol/base/pymod/export_residue.cc @@ -22,7 +22,7 @@ using namespace boost::python; #include <ost/mol/mol.hh> - +#include <ost/export_helper/vector.hh> using namespace ost; using namespace ost::mol; @@ -71,6 +71,7 @@ void export_Residue() .def(self+int()) .def(self-int()) ; + implicitly_convertible<int, ResNum>(); { scope sec_struct_scope=class_<SecStructure>("SecStructure", init<>()) .def(init<char>()) @@ -174,5 +175,6 @@ void export_Residue() class_<ResidueHandleList>("ResidueHandleList", no_init) .def(vector_indexing_suite<ResidueHandleList>()) + .def(ost::VectorAdditions<ResidueHandleList>()) ; } diff --git a/modules/mol/base/pymod/export_residue_view.cc b/modules/mol/base/pymod/export_residue_view.cc index 29943f54a99392eb06afce6d84d91ffe9e0d4da6..a23bcf88d418a6110ce291278bdf090272ca29df 100644 --- a/modules/mol/base/pymod/export_residue_view.cc +++ b/modules/mol/base/pymod/export_residue_view.cc @@ -22,7 +22,7 @@ using namespace boost::python; #include <ost/mol/mol.hh> - +#include <ost/export_helper/vector.hh> using namespace ost; using namespace ost::mol; @@ -48,6 +48,7 @@ void export_ResidueView() { class_<ResidueViewList>("ResidueViewList", no_init) .def(vector_indexing_suite<ResidueViewList>()) + .def(ost::VectorAdditions<ResidueViewList>()) ; void (ResidueView::* apply1)(EntityVisitor&) = &ResidueView::Apply; diff --git a/modules/mol/base/pymod/export_surface.cc b/modules/mol/base/pymod/export_surface.cc index 71c347e16574622488c6a83eb63dc62aa62e2fc8..fe0d98fa15f937ef578780aeaf6f9ddf9bf4725d 100644 --- a/modules/mol/base/pymod/export_surface.cc +++ b/modules/mol/base/pymod/export_surface.cc @@ -24,7 +24,6 @@ using namespace boost::python; #include <ost/mol/surface_handle.hh> #include <ost/mol/surface_builder.hh> #include <ost/mol/entity_handle.hh> -#include <ost/mol/impl/rsurf_impl.hh> #include <ost/mol/impl/surface_impl.hh> using namespace ost; @@ -37,12 +36,6 @@ SurfaceHandle create1() return CreateSurface(); } -void rsurf_tri_dummy(rsurf::RSurf& rs, float patch_size) -{ - impl::SurfaceImplP impl(new impl::SurfaceImpl()); - rs.Triangulate(impl,patch_size); -} - void (SurfaceHandle::*attach1)(const EntityHandle&,Real)=&SurfaceHandle::Attach; void (SurfaceHandle::*attach2)(const EntityView&,Real)=&SurfaceHandle::Attach; @@ -74,10 +67,4 @@ void export_Surface() def("CreateSurface",create1); def("BuildSurface",BuildSurface); - - class_<rsurf::RSurf,rsurf::RSurfP>("RSurf", init<Real>()) - .def("AddSphere",&rsurf::RSurf::AddSphere) - .def("Build",&rsurf::RSurf::Build) - .def("Triangulate",rsurf_tri_dummy) - ; } diff --git a/modules/mol/base/pymod/wrap_mol.cc b/modules/mol/base/pymod/wrap_mol.cc index 82a449f681fbe98866c42acb0b8581fefd66d331..ce55b9942f8f5fd378ce11c78b924b6b5691a44d 100644 --- a/modules/mol/base/pymod/wrap_mol.cc +++ b/modules/mol/base/pymod/wrap_mol.cc @@ -41,6 +41,7 @@ void export_CoordGroup(); void export_PropertyID(); void export_BoundingBox(); void export_QueryViewWrapper(); +void export_EntityPropertyMapper(); BOOST_PYTHON_MODULE(_mol) { export_Entity(); @@ -61,7 +62,7 @@ BOOST_PYTHON_MODULE(_mol) export_PropertyID(); export_BoundingBox(); export_QueryViewWrapper(); - + export_EntityPropertyMapper(); class_<Transform>("Transform", init<>()) .def("GetMatrix",&Transform::GetMatrix) .def("GetTransposedMatrix",&Transform::GetTransposedMatrix) diff --git a/modules/mol/base/src/atom_base.cc b/modules/mol/base/src/atom_base.cc index 8eaff3164a27365f42b981a80495e6eb1c9f93f1..2818844b012bb0ac1d8ef0d2f088fb7435128434 100644 --- a/modules/mol/base/src/atom_base.cc +++ b/modules/mol/base/src/atom_base.cc @@ -120,12 +120,6 @@ void AtomBase::CheckValidity() const throw InvalidHandle(); } -long AtomBase::GetHashCode() const -{ - this->CheckValidity(); - return reinterpret_cast<long>(Impl().get()); -} - std::ostream& operator<<(std::ostream& os, const AtomBase& atom) { if (atom.IsValid()) { diff --git a/modules/mol/base/src/atom_base.hh b/modules/mol/base/src/atom_base.hh index 142f1a9db2acab1949bef593ff7a99b5715230c1..9777aea714732f090c4b2def487086e4031ad26f 100644 --- a/modules/mol/base/src/atom_base.hh +++ b/modules/mol/base/src/atom_base.hh @@ -153,11 +153,6 @@ public: /// \brief get atom implementation impl::AtomImplPtr& Impl(); - /// \brief Get unique identifier for atom - /// - /// Get hash code that uniquely identifies every atom. The hash code is - /// identical for all atom views pointing to a given atom. - long GetHashCode() const; protected: GenericPropContainerImpl* GpImpl(); diff --git a/modules/mol/base/src/atom_handle.cc b/modules/mol/base/src/atom_handle.cc index 486441683eb4deb5913d8830ae9aba18d1cce020..61c975724e70f6c913321947ff31e406133aa5a8 100644 --- a/modules/mol/base/src/atom_handle.cc +++ b/modules/mol/base/src/atom_handle.cc @@ -116,6 +116,12 @@ AtomHandle AtomHandle::GetHandle() const return *this; } +long AtomHandle::GetHashCode() const +{ + this->CheckValidity(); + return reinterpret_cast<long>(Impl().get()); +} + }} // ns diff --git a/modules/mol/base/src/atom_handle.hh b/modules/mol/base/src/atom_handle.hh index 7d817f8e169a7f1f38581b41a53697bc0bad2a66..6ea9094c0db51dab69bc7c46b8a5913c2402404b 100644 --- a/modules/mol/base/src/atom_handle.hh +++ b/modules/mol/base/src/atom_handle.hh @@ -81,6 +81,13 @@ public: /// /// Useful for duck-typing in Python and templated code. AtomHandle GetHandle() const; + + /// \brief Get unique identifier for atom + /// + /// Get hash code that uniquely identifies every atom. The hash code is + /// identical for all atom views pointing to a given atom. + long GetHashCode() const; + bool operator==(const AtomHandle& ref) const; bool operator!=(const AtomHandle& ref) const; diff --git a/modules/mol/base/src/atom_view.cc b/modules/mol/base/src/atom_view.cc index 25518778e9164600b08b817e17c48bf3cbb4a0c3..5811a2d5567ea3db1de2ebe8eede8fb4c9a7c631 100644 --- a/modules/mol/base/src/atom_view.cc +++ b/modules/mol/base/src/atom_view.cc @@ -115,7 +115,7 @@ mol::AtomViewList AtomView::GetBondPartners() const mol::AtomViewList avl; mol::BondHandleList::const_iterator i; for (i=data_->bonds.begin();i!=data_->bonds.end();++i) { - if (i->GetFirst()!=*this) { + if (i->GetFirst().GetHandle()!=this->GetHandle()) { avl.push_back(this->GetEntity().FindAtom(i->GetFirst())); } else { avl.push_back(this->GetEntity().FindAtom(i->GetSecond())); @@ -156,7 +156,13 @@ void AtomView::RemoveBondInternal(const BondHandle& bond) data_->bonds.erase(i); } } - + +long AtomView::GetHashCode() const +{ + this->CheckValidity(); + return reinterpret_cast<long>(data_.get()); +} + }} // ns diff --git a/modules/mol/base/src/atom_view.hh b/modules/mol/base/src/atom_view.hh index ad65accc6f155ee28c54248b9178fb2b502fb563..a9e2d9937986b83b3b10d6e547afe2b90c1c6e53 100644 --- a/modules/mol/base/src/atom_view.hh +++ b/modules/mol/base/src/atom_view.hh @@ -69,6 +69,11 @@ public: void Apply(EntityVisitor& visitor); void Apply(EntityViewVisitor& visitor); + /// \brief get unique id + /// + /// The unique id is the same for all AtomViews pointing to the same atom + /// view data. + long GetHashCode() const; bool operator==(const AtomView& rhs) const; bool operator!=(const AtomView& rhs) const; protected: diff --git a/modules/mol/base/src/chain_handle.cc b/modules/mol/base/src/chain_handle.cc index 156eca176a4d4b8b54a120e56f1f384bb87e78f2..4581eb7806890f1a12da761cfd6ac18ba906857e 100644 --- a/modules/mol/base/src/chain_handle.cc +++ b/modules/mol/base/src/chain_handle.cc @@ -125,17 +125,18 @@ bool ChainHandle::operator!=(const ChainHandle& ref) const ResidueHandleIter ChainHandle::ResiduesBegin() const { this->CheckValidity(); impl::ChainImplPtr c=Impl(); - impl::ChainImplMap::iterator cc=c->GetEntity()->GetChainMap().find(c->GetName()); - return ResidueHandleIter(cc, c->GetResidueList().begin(), c->GetEntity()); + impl::ChainImplList::iterator cc=c->GetEntity()->GetChain(this->GetName()); + return ResidueHandleIter(cc, c->GetResidueList().begin(), + c->GetEntity()); } ResidueHandleIter ChainHandle::ResiduesEnd() const { this->CheckValidity(); impl::ChainImplPtr c=Impl(); - impl::ChainImplMap::iterator cc=c->GetEntity()->GetChainMap().find(c->GetName()); - impl::ChainImplMap::iterator nc=cc; ++nc; - if (nc!=c->GetEntity()->GetChainMap().end()) { - return ResidueHandleIter(nc, nc->second->GetResidueList().begin(), + impl::ChainImplList::iterator cc=c->GetEntity()->GetChain(this->GetName()); + impl::ChainImplList::iterator nc=cc; ++nc; + if (nc!=c->GetEntity()->GetChainList().end()) { + return ResidueHandleIter(nc, (*nc)->GetResidueList().begin(), c->GetEntity()); } else { return ResidueHandleIter(cc, c->GetResidueList().end(), @@ -151,7 +152,7 @@ AtomHandleIter ChainHandle::AtomsBegin() const return AtomHandleIter(); } - impl::ChainImplMap::iterator cc=c->GetEntity()->GetChainMap().find(c->GetName()); + impl::ChainImplList::iterator cc=c->GetEntity()->GetChain(this->GetName()); return AtomHandleIter(cc, c->GetResidueList().begin(), c->GetResidueList().front()->GetAtomList().begin(), c->GetEntity(), true); @@ -164,10 +165,10 @@ AtomHandleIter ChainHandle::AtomsEnd() const { if (c->GetResidueList().empty()) { return AtomHandleIter(); } - impl::ChainImplMap::iterator cc=c->GetEntity()->GetChainMap().find(c->GetName()); - impl::ChainImplMap::iterator nc=cc; ++nc; - impl::ResidueImplList& rc=nc->second->GetResidueList(); - if (nc!=c->GetEntity()->GetChainMap().end()) { + impl::ChainImplList::iterator cc=c->GetEntity()->GetChain(this->GetName()); + impl::ChainImplList::iterator nc=cc; ++nc; + impl::ResidueImplList& rc=(*nc)->GetResidueList(); + if (nc!=c->GetEntity()->GetChainList().end()) { return AtomHandleIter(nc, rc.begin(), rc.front()->GetAtomList().begin(), c->GetEntity(), false); } else { diff --git a/modules/mol/base/src/coord_source.cc b/modules/mol/base/src/coord_source.cc index 9b9f853e32e18e1f237a98458f7bfc85e24545ea..0afa3597dacfba19e28d790f0a606d7311256877 100644 --- a/modules/mol/base/src/coord_source.cc +++ b/modules/mol/base/src/coord_source.cc @@ -95,7 +95,7 @@ void CoordSource::CaptureInto(int pos) e=atoms_.end(); i!=e; ++i) { coords.push_back(i->GetPos()); } - if(pos<0 || pos>=GetFrameCount()) { + if(pos<0 || pos>=static_cast<int>(this->GetFrameCount())) { this->AddFrame(coords); } else { this->InsertFrame(pos,coords); diff --git a/modules/mol/base/src/entity_handle.cc b/modules/mol/base/src/entity_handle.cc index b0ac01f09e135c5110bf970af372b13ebbf14590..8686df88c286c726648bad9abec259514414a9c2 100644 --- a/modules/mol/base/src/entity_handle.cc +++ b/modules/mol/base/src/entity_handle.cc @@ -257,48 +257,48 @@ AtomHandle EntityHandle::FindAtom(const String& chain_name, ResidueHandleIter EntityHandle::ResiduesBegin() const { this->CheckValidity(); - if (Impl()->GetChainMap().empty()) { + if (Impl()->GetChainList().empty()) { return ResidueHandleIter(); } impl::EntityImplPtr i=Impl(); - impl::ChainImplPtr chain=i->GetChainMap().begin()->second; - return ResidueHandleIter(i->GetChainMap().begin(), + impl::ChainImplPtr chain=i->GetChainList().front(); + return ResidueHandleIter(i->GetChainList().begin(), chain->GetResidueList().begin(), i); } ResidueHandleIter EntityHandle::ResiduesEnd() const { this->CheckValidity(); - if (Impl()->GetChainMap().empty()) { + if (Impl()->GetChainList().empty()) { return ResidueHandleIter(); } impl::EntityImplPtr i=Impl(); - impl::ChainImplPtr chain=i->GetChainMap().rbegin()->second; - return ResidueHandleIter(i->GetChainMap().end(), + impl::ChainImplPtr chain=i->GetChainList().back(); + return ResidueHandleIter(i->GetChainList().end(), chain->GetResidueList().end(), i); } ChainHandleIter EntityHandle::ChainsBegin() const { this->CheckValidity(); - return ChainHandleIter(Impl()->GetChainMap().begin()); + return ChainHandleIter(Impl()->GetChainList().begin()); } ChainHandleIter EntityHandle::ChainsEnd() const { - return ChainHandleIter(Impl()->GetChainMap().end()); + return ChainHandleIter(Impl()->GetChainList().end()); } AtomHandleIter EntityHandle::AtomsBegin() const { this->CheckValidity(); impl::EntityImplPtr ent=Impl(); - if (ent->GetChainMap().empty()) { + if (ent->GetChainList().empty()) { return AtomHandleIter(); } - impl::ResidueImplList& r=ent->GetChainMap().begin()->second->GetResidueList(); + impl::ResidueImplList& r=ent->GetChainList().front()->GetResidueList(); if (r.empty()) { return AtomHandleIter(); } - return AtomHandleIter(ent->GetChainMap().begin(), r.begin(), + return AtomHandleIter(ent->GetChainList().begin(), r.begin(), r.front()->GetAtomList().begin(), ent, true); } @@ -306,14 +306,14 @@ AtomHandleIter EntityHandle::AtomsEnd() const { this->CheckValidity(); impl::EntityImplPtr ent=Impl(); - if (ent->GetChainMap().empty()) { + if (ent->GetChainList().empty()) { return AtomHandleIter(); } - impl::ResidueImplList& r=ent->GetChainMap().rbegin()->second->GetResidueList(); + impl::ResidueImplList& r=ent->GetChainList().back()->GetResidueList(); if (r.empty()) { return AtomHandleIter(); } - return AtomHandleIter(ent->GetChainMap().end(), r.end(), + return AtomHandleIter(ent->GetChainList().end(), r.end(), r.back()->GetAtomList().end(), ent, false); } diff --git a/modules/mol/base/src/entity_view.cc b/modules/mol/base/src/entity_view.cc index 34f7d506421cef9b32aeaec3c46a0470d89c3f2c..a3819e1020d4c8dd975f9b2e799d4bf248092a34 100644 --- a/modules/mol/base/src/entity_view.cc +++ b/modules/mol/base/src/entity_view.cc @@ -76,9 +76,9 @@ EntityView::EntityView(const EntityHandle& entity, ViewAddFlags flags) : EntityBase(entity.Impl()), data_(new EntityViewData()) { if (flags & ViewAddFlag::INCLUDE_CHAINS) { - impl::ChainImplMap::const_iterator i=entity.Impl()->GetChainMap().begin(); - for (; i!=entity.Impl()->GetChainMap().end(); ++i) { - this->AddChain(ChainHandle(i->second), flags); + impl::ChainImplList::const_iterator i=entity.Impl()->GetChainList().begin(); + for (; i!=entity.Impl()->GetChainList().end(); ++i) { + this->AddChain(ChainHandle(*i), flags); } } } diff --git a/modules/mol/base/src/impl/CMakeLists.txt b/modules/mol/base/src/impl/CMakeLists.txt index c398ff177dc8170df6b30271771d768be4417652..3de4864e7a11e9dd29904fd60f997bab8cec2e51 100644 --- a/modules/mol/base/src/impl/CMakeLists.txt +++ b/modules/mol/base/src/impl/CMakeLists.txt @@ -9,7 +9,6 @@ query_ast.cc query_impl.cc residue_impl.cc surface_impl.cc -rsurf_impl.cc torsion_impl.cc PARENT_SCOPE ) @@ -34,7 +33,6 @@ residue_impl.hh residue_impl_fw.hh surface_impl.hh surface_impl_fw.hh -rsurf_impl.hh torsion_impl.hh torsion_impl_fw.hh PARENT_SCOPE diff --git a/modules/mol/base/src/impl/chain_impl_fw.hh b/modules/mol/base/src/impl/chain_impl_fw.hh index 00f22561b72845bea621bd31f90c1587e886631d..2ba9c725dbf40038cf67f76b6749bdd5f0293fa2 100644 --- a/modules/mol/base/src/impl/chain_impl_fw.hh +++ b/modules/mol/base/src/impl/chain_impl_fw.hh @@ -28,7 +28,6 @@ namespace ost { namespace mol { namespace impl { class ChainImpl; typedef boost::shared_ptr<ChainImpl> ChainImplPtr; typedef boost::weak_ptr<ChainImpl> ChainImplW; -typedef std::list<ChainImplPtr> ChainImplList; }}} // ns diff --git a/modules/mol/base/src/impl/entity_impl.cc b/modules/mol/base/src/impl/entity_impl.cc index 29fdad970ebddf5f8a8a49e54a436182bbc1c068..c7eb101630db5e9723d848b50fa4abec29d3f2f7 100644 --- a/modules/mol/base/src/impl/entity_impl.cc +++ b/modules/mol/base/src/impl/entity_impl.cc @@ -64,7 +64,7 @@ namespace ost { namespace mol { namespace impl { EntityImpl::EntityImpl(): atom_map_(), - chain_map_(), + chain_list_(), connector_map_(), torsion_map_(), transformation_matrix_(), @@ -104,9 +104,9 @@ mol::BondHandleList EntityImpl::GetBondList() const int EntityImpl::GetResidueCount() const { int count=0; - for (ChainImplMap::const_iterator i=chain_map_.begin(), - e=chain_map_.end(); i!=e; ++i) { - count+=i->second->GetResidueCount(); + for (ChainImplList::const_iterator i=chain_list_.begin(), + e=chain_list_.end(); i!=e; ++i) { + count+=(*i)->GetResidueCount(); } return count; } @@ -133,9 +133,9 @@ ChainImplPtr EntityImpl::InsertChain(const ChainImplPtr& chain) void EntityImpl::ReplicateHierarchy(EntityImplPtr dest) { - for (ChainImplMap::const_iterator i=chain_map_.begin(), - e1=chain_map_.end(); i!=e1; ++i) { - ChainImplPtr src_chain=i->second; + for (ChainImplList::const_iterator i=chain_list_.begin(), + e1=chain_list_.end(); i!=e1; ++i) { + ChainImplPtr src_chain=*i; ChainImplPtr dst_chain=dest->InsertChain(src_chain); // copy generic properties dst_chain->Assign(*src_chain.get()); @@ -176,10 +176,10 @@ AtomImplPtr lookup_atom(const AtomImplPtr& atom, EntityImplPtr dest, void EntityImpl::DoCopyBondsAndTorsions(EntityImplPtr dest) { - for (ChainImplMap::const_iterator i=chain_map_.begin(), - i2=dest->chain_map_.begin(), e1=chain_map_.end(); i!=e1; ++i, ++i2) { - ChainImplPtr src_chain=i->second; - ChainImplPtr dst_chain=i2->second; + for (ChainImplList::const_iterator i=chain_list_.begin(), + i2=dest->chain_list_.begin(), e1=chain_list_.end(); i!=e1; ++i, ++i2) { + ChainImplPtr src_chain=*i; + ChainImplPtr dst_chain=*i2; for (ResidueImplList::iterator j=src_chain->GetResidueList().begin(), j2=dst_chain->GetResidueList().begin(), e2=src_chain->GetResidueList().end(); j!=e2; ++j, ++j2) { @@ -236,7 +236,7 @@ void EntityImpl::DoCopy(EntityImplPtr dest) int EntityImpl::GetChainCount() const { - return static_cast<int>(chain_map_.size()); + return static_cast<int>(chain_list_.size()); } const geom::Mat4& EntityImpl::GetTransfMatrix() const @@ -384,17 +384,19 @@ ResidueImplPtr EntityImpl::CreateResidue(const ChainImplPtr& cp, ChainImplPtr EntityImpl::InsertChain(const String& cname) { - ChainImplMap::iterator i=chain_map_.find(cname); - if (i!=chain_map_.end()) { - throw IntegrityError("Can't insert chain. A chain with name '"+cname+ - "' already exists"); + for (ChainImplList::iterator + i=chain_list_.begin(), e=chain_list_.end(); i!=e; ++i) { + if ((*i)->GetName()==cname) { + throw IntegrityError("Can't insert chain. A chain with name '"+cname+ + "' already exists"); + } } #if MAKE_SHARED_AVAILABLE ChainImplPtr cp=boost::make_shared<ChainImpl>(shared_from_this(), cname); #else ChainImplPtr cp(new ChainImpl(shared_from_this(), cname)); #endif - chain_map_.insert(ChainImplMap::value_type(cp->GetName(),cp)); + chain_list_.push_back(cp); return cp; } @@ -767,8 +769,9 @@ void EntityImpl::Apply(EntityVisitor& v) { LOG_TRACE("visitor @" << &v << " visiting entity impl @" << this << std::endl); v.OnEntry(); - for(ChainImplMap::iterator it = chain_map_.begin();it!=chain_map_.end();++it) { - it->second->Apply(v); + for(ChainImplList::iterator + it = chain_list_.begin();it!=chain_list_.end();++it) { + (*it)->Apply(v); } for(ConnectorImplMap::iterator it = connector_map_.begin();it!=connector_map_.end();++it) { @@ -821,7 +824,7 @@ void EntityImpl::NotifyObserver() void EntityImpl::Swap(EntityImpl& impl) { atom_map_.swap(impl.atom_map_); - chain_map_.swap(impl.chain_map_); + chain_list_.swap(impl.chain_list_); connector_map_.swap(impl.connector_map_); torsion_map_.swap(impl.torsion_map_); std::swap(transformation_matrix_,impl.transformation_matrix_); @@ -830,15 +833,6 @@ void EntityImpl::Swap(EntityImpl& impl) observer_map_.swap(impl.observer_map_); } -ChainImplList EntityImpl::GetChainList() const { - ChainImplList cl; - ChainImplMap::const_iterator i; - for (i=chain_map_.begin(); i!=chain_map_.end(); ++i) { - cl.push_back(i->second); - } - return cl; -} - TorsionImplP EntityImpl::FindTorsion(const AtomImplPtr& a1, const AtomImplPtr& a2, @@ -895,19 +889,15 @@ EntityView EntityImpl::do_selection(const EntityHandle& eh, EntityHandle myself(const_cast<impl::EntityImpl*>(this)->shared_from_this()); QueryState qs(query.CreateQueryState(myself)); LOGN_DUMP("entering chain loop"); - for (ChainImplMap::const_iterator ch_it = chain_map_.begin(); - ch_it!=chain_map_.end();++ch_it) { - if(!ch_it->second) { - LOGN_DUMP("found invalid chain shared_ptr"); - continue; - } - LOGN_DUMP("checking chain " << ch_it->second->GetName()); + for (ChainImplList::const_iterator + ch_it=chain_list_.begin(); ch_it!=chain_list_.end();++ch_it) { + LOGN_DUMP("checking chain " << (*ch_it)->GetName()); c_added = false; - tribool c = always_true ? tribool(true) : qs.EvalChain(ch_it->second); + tribool c = always_true ? tribool(true) : qs.EvalChain(*ch_it); if (c == true) { LOGN_DUMP("chain is selected"); // Include all residues - const ChainImplPtr& ci=ch_it->second; + const ChainImplPtr& ci=*ch_it; ++chain_count; ChainView chain=view.AddChain(ci); ResidueImplList::const_iterator re_it = ci->GetResidueList().begin(); @@ -930,7 +920,7 @@ EntityView EntityImpl::do_selection(const EntityHandle& eh, } else if (indeterminate(c)) { // Test residues r_added = false; - const ChainImplPtr& ci = ch_it->second; + const ChainImplPtr& ci = *ch_it; ChainView chain; ResidueImplList::const_iterator re_it = ci->GetResidueList().begin(); @@ -1042,10 +1032,10 @@ EntityView EntityImpl::CreateFullView(const EntityHandle& h) const } ChainImplPtr EntityImpl::FindChain(const String& name) const { - ChainImplMap::const_iterator i; - for(i=chain_map_.begin(); i!=chain_map_.end();++i) { - if (i->second->GetName()==name) - return i->second; + ChainImplList::const_iterator i; + for(i=chain_list_.begin(); i!=chain_list_.end();++i) { + if ((*i)->GetName()==name) + return *i; } return ChainImplPtr(); } @@ -1078,7 +1068,7 @@ TorsionImplMap& EntityImpl::GetTorsionMap() { void EntityImpl::DeleteChain(const ChainImplPtr& chain) { if (chain && chain->GetEntity().get()==this) { chain->DeleteAllResidues(); - chain_map_.erase(chain->GetName()); + chain_list_.erase(this->GetChain(chain->GetName())); } } @@ -1191,24 +1181,26 @@ void EntityImpl::DecICSEditorCount() } } +impl::ChainImplList::iterator EntityImpl::GetChain(const String& name) +{ + impl::ChainImplList& cc=this->GetChainList(); + for (impl::ChainImplList::iterator i=cc.begin(), e=cc.end(); i!=e; ++i) { + if ((*i)->GetName()==name) { + return i; + } + } + return cc.end(); +} void EntityImpl::RenameChain(ChainImplPtr chain, const String& new_name) { - ChainImplMap::iterator i, j; - j=chain_map_.find(new_name); - - if (j!=chain_map_.end() && j->second!=chain) { + ChainImplList::iterator i; + ChainImplPtr ch=this->FindChain(new_name); + if (ch) { throw IntegrityError("unable to rename chain '"+chain->GetName()+ "' to '"+new_name+"', since there is already a chain " "with that name"); } - for(i=chain_map_.begin(); i!=chain_map_.end();++i) { - if (i->second==chain) { - chain_map_.erase(i); - chain_map_.insert(std::make_pair(new_name, chain)); - chain->SetName(new_name); - break; - } - } + chain->SetName(new_name); } void EntityImpl::UpdateTransformedPos(){ diff --git a/modules/mol/base/src/impl/entity_impl.hh b/modules/mol/base/src/impl/entity_impl.hh index 63504c74987765914620394ab72515b64031090c..81f533bf0a9f3c696276b7e5e487e14a7125bfaa 100644 --- a/modules/mol/base/src/impl/entity_impl.hh +++ b/modules/mol/base/src/impl/entity_impl.hh @@ -56,7 +56,7 @@ typedef std::map<AtomImpl*,AtomImplPtr> AtomImplMap; /// \internal typedef std::map<ResidueImpl*,ResidueImplPtr> ResidueImplMap; /// \internal -typedef std::map<String,ChainImplPtr> ChainImplMap; +typedef std::vector<ChainImplPtr> ChainImplList; /// \internal typedef std::map<ConnectorImpl*,ConnectorImplP> ConnectorImplMap; /// \internal @@ -201,10 +201,9 @@ public: bool IsTransfIdentity() const; - ChainImplList GetChainList() const; + const ChainImplList& GetChainList() const { return chain_list_; } - ChainImplMap& GetChainMap() {return chain_map_; } - const ChainImplMap& GetChainMap() const {return chain_map_; } + ChainImplList& GetChainList() { return chain_list_; } void DeleteFromConnMap(const ConnectorImplP& conn); @@ -241,6 +240,8 @@ public: const String& GetName() const; + impl::ChainImplList::iterator GetChain(const String& name); + void SetName(const String& ent_name); private: @@ -251,7 +252,7 @@ private: void DoCopyBondsAndTorsions(EntityImplPtr dest); AtomImplMap atom_map_; - ChainImplMap chain_map_; + ChainImplList chain_list_; ConnectorImplMap connector_map_; TorsionImplMap torsion_map_; diff --git a/modules/mol/base/src/impl/rsurf_impl.cc b/modules/mol/base/src/impl/rsurf_impl.cc deleted file mode 100644 index 283671fdf161989a2db83c5cc4fdc357b9769125..0000000000000000000000000000000000000000 --- a/modules/mol/base/src/impl/rsurf_impl.cc +++ /dev/null @@ -1,1090 +0,0 @@ -//------------------------------------------------------------------------------ -// This file is part of the OpenStructure project <www.openstructure.org> -// -// Copyright (C) 2008-2010 by the OpenStructure authors -// -// This library is free software; you can redistribute it and/or modify it under -// the terms of the GNU Lesser General Public License as published by the Free -// Software Foundation; either version 3.0 of the License, or (at your option) -// any later version. -// This library is distributed in the hope that it will be useful, but WITHOUT -// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -// details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this library; if not, write to the Free Software Foundation, Inc., -// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -//------------------------------------------------------------------------------ -/* - Author: Ansgar Philippsen -*/ - -/* - parallelization notes: - - during the build round, ie the recursive travel along - the surface to identify the reduced surface points, the - majority of calls depends on the previous one, and the - core algorithm is a recursive traversal; it is unclear - how to add parallelization to this type of logic. - - during the triangulization, the creation of the patches, - the saddles and the sphere caps are in their internal - loop independent from each other; the only restriction - in terms of sequence is that the patches must be complete - before the saddles are build, and the patches must be - complete prior to the sphere caps. - -*/ - -#include <cmath> - -#include <ost/mol/entity_view.hh> -#include <ost/mol/impl/rsurf_impl.hh> -#include <ost/mol/impl/surface_impl.hh> - -#include <ost/geom/geom.hh> -#include <ost/log.hh> - -namespace ost { namespace mol { namespace rsurf { - -using namespace geom; - -// almost copy from gfx... bad -// TODO: refactor to geom -void build_sphere(int level, - std::vector<Vec3>& vlist, - std::vector<uint>& ilist) -{ - vlist.clear(); - ilist.clear(); - unsigned int step1 = level*4; - unsigned int step2 = level*2; - Real fact1 = M_PI*2.0/static_cast<Real>(step1); - Real fact2 = M_PI/static_cast<Real>(step2); - - vlist.push_back(geom::Vec3(0.0,1.0,0.0)); - for(unsigned int i=0;i<step1;++i) { - for(unsigned int k=1;k<step2;++k) { - Real ii = M_PI+fact1*static_cast<Real>(i); - Real kk = fact2*static_cast<Real>(k); - vlist.push_back(geom::Vec3(sin(kk)*cos(ii), cos(kk), sin(kk)*sin(ii))); - } - } - vlist.push_back(geom::Vec3(0.0,-1.0,0.0)); - - unsigned int point_count=vlist.size(); - - // top - unsigned int j=1; - for(unsigned int i=0;i<step1;++i) { - unsigned int k=i+1; - k%=step1; - ilist.push_back(0); - ilist.push_back(k*(step2-1)+j); - ilist.push_back(i*(step2-1)+j); - } - - // bottom - j=step2-1; - for(unsigned int i=0;i<step1;++i) { - unsigned int k=i+1; - k%=step1; - ilist.push_back(point_count-1); - ilist.push_back(i*(step2-1)+j); - ilist.push_back(k*(step2-1)+j); - } - - // middle - for(unsigned int i=0;i<step1;++i) { - unsigned int k=i+1; - k%=step1; - for(unsigned j=1;j<step2-1;++j) { - unsigned l=j+1; - l%=(step2); - // add 2 triangles, counterclockwise - unsigned int p1=i*(step2-1)+j; - unsigned int p2=i*(step2-1)+l; - unsigned int p3=k*(step2-1)+j; - unsigned int p4=k*(step2-1)+l; - ilist.push_back(p1); - ilist.push_back(p3); - ilist.push_back(p2); - ilist.push_back(p2); - ilist.push_back(p3); - ilist.push_back(p4); - } - } -} - - -Arc::Arc() -{} - -Arc::Arc(const SphereP& h, const SphereP& k, const SphereP& s): - H(h), K(k), S(s), T() -{ - Vec3 o=h->pos; - Vec3 d=o-k->pos; - Vec3 p=s->pos; - - Real r = (Dot(d,p)-Dot(d,o))/Dot(d,d); - axis = Normalize(d); - fixpoint = o+r*d; - sdir = Normalize(p-fixpoint); - tdir=Vec3(0,0,0); - - // transformation matrix into normalized system, for calc_phi - Vec3 orth = Normalize(Cross(axis,sdir)); - xmat = Mat3(sdir[0],sdir[1],sdir[2], - orth[0],orth[1],orth[2], - axis[0],axis[1],axis[2]); - - LOGN_DUMP("new arc"); - LOGN_DUMP(" " << H->name << " " << K->name); - LOGN_DUMP(" ax=" << axis << " fp=" << fixpoint << " sd=" << sdir << " ax.sd=" << Dot(axis,sdir)); -} - -void Arc::SetT(const SphereP& t) -{ - T=t; - tdir=Normalize(t->pos-fixpoint); -} - -Tet::Tet(const SphereP& a, const SphereP& b, const SphereP& c, const Sphere& s): - A(a), B(b), C(c), S(new Sphere(s)) -{ - init(); -} - -Tet::Tet(const SphereP& a, const SphereP& b, const SphereP& c, const SphereP& s): - A(a), B(b), C(c), S(s) -{ - init(); -} - -void Tet::init() -{ - LOGN_DUMP("new tet"); - LOGN_DUMP(" " << A->name << " " << B->name << " " << C->name); - LOGN_DUMP(" " << S->pos); - LOGN_DUMP(" a-s: " << Length(A->pos-S->pos) << " " << A->rad+S->rad); - LOGN_DUMP(" b-s: " << Length(B->pos-S->pos) << " " << B->rad+S->rad); - LOGN_DUMP(" c-s: " << Length(C->pos-S->pos) << " " << C->rad+S->rad); - Real ps = Dot(Cross(A->pos-B->pos,C->pos-B->pos),S->pos-(A->pos+B->pos+C->pos)/3.0); - LOGN_DUMP(" p.s: " << ps ); - if(ps<0.0) { - LOGN_DUMP(" swapping B/C for correct parity"); - std::swap(B,C); - parity_swap=true; - } else { - parity_swap=false; - } - cA=S->pos+(S->rad/(S->rad+A->rad))*(A->pos-S->pos); - cB=S->pos+(S->rad/(S->rad+B->rad))*(B->pos-S->pos); - cC=S->pos+(S->rad/(S->rad+C->rad))*(C->pos-S->pos); -} - -ArcP Tet::GetArc(const SphereP& h, const SphereP& k) -{ - if(U->H==h && U->K==k) return U; - else if(U->H==k && U->K==h) return U; - else if(V->H==h && V->K==k) return V; - else if(V->H==k && V->K==h) return V; - else if(W->H==h && W->K==k) return W; - else if(W->H==k && W->K==h) return W; - return ArcP(); -} - - -RSurf::RSurf(Real probe_radius): - sphere_list_(), - arc_list_(), - tet_list_(), - probe_radius_(probe_radius), - max_rad_(0.0), - spat_org_(probe_radius_*2.0) -{} - -void RSurf::AddSphere(const Vec3& pos, Real rad, const String& name) -{ - sphere_list_.push_back(SphereP(new Sphere(pos,rad))); - sphere_list_.back()->name=name; - spat_org_.Add(sphere_list_.back(),pos); - max_rad_=std::max(max_rad_,rad); -} - -namespace { -bool comp(const Vec3& p1, const Vec3& p2) -{ - return p1[2]!=p2[2] ? p1[2]<p2[2] : (p1[1]!=p2[1] ? p1[1]<p2[1] : p1[0]<p2[0]); -} -} - -void RSurf::Build() -{ - LOGN_DUMP("entering RSurf::Build"); - for(SphereList::iterator it=sphere_list_.begin();it!=sphere_list_.end();++it) { - LOGN_DUMP("sphere " << it->get() << " @ " << (*it)->pos); - } - - // find sphere with lowest extension in order z,y,x - SphereP best_a=*(sphere_list_.begin()); - Vec3 best_pos=best_a->pos-Vec3(best_a->rad,best_a->rad,best_a->rad); - for(SphereList::iterator it=sphere_list_.begin();it!=sphere_list_.end();++it) { - // radius corrected - Vec3 pp=(*it)->pos-Vec3((*it)->rad,(*it)->rad,(*it)->rad); - if(comp(pp,best_pos)) { - best_a=*it; - best_pos=pp; - } - } - - // a temporary solvent sphere, only touching best_a - SphereP temp_s(new Sphere(best_a->pos-Vec3(0,0,best_a->rad+probe_radius_),probe_radius_)); - // a temporary arc to find the second starting sphere - ArcP temp_arc(new Arc()); - temp_arc->S=temp_s; - temp_arc->axis = Vec3(-1,0,0); - temp_arc->fixpoint = best_a->pos; - temp_arc->sdir = Vec3(0,0,-1); - Vec3 orth = Normalize(Cross(temp_arc->axis,temp_arc->sdir)); - temp_arc->xmat = Mat3(temp_arc->sdir[0],temp_arc->sdir[1],temp_arc->sdir[2], - orth[0],orth[1],orth[2], - temp_arc->axis[0],temp_arc->axis[1],temp_arc->axis[2]); - - // find best second sphere - almost identical to find_best_tet() - SphereList clist = get_nearest_spheres(best_a->pos, best_a,best_a); - Real best_phi = 7.0; - SphereP best_b; - - for(SphereList::const_iterator it=clist.begin();it!=clist.end();++it) { - Real phi = calc_phi(temp_arc,*it,false); - if(phi>=0.0 && phi<best_phi) { - best_phi = phi; - best_b = *it; - } - } - - if(!best_b) { - LOGN_MESSAGE("singular sphere detected, no reduced surface build"); - return; - } - - // rotate solvent around axis to get updated pos - temp_s->pos = AxisRotation(temp_arc->axis,best_phi)* - (temp_s->pos-temp_arc->fixpoint)+ - temp_arc->fixpoint; - - // now find third sphere with updated temporary arc - again similar to find_best_tet() - temp_arc = ArcP(new Arc(best_a,best_b,temp_s)); - - clist = get_nearest_spheres(temp_arc->fixpoint,best_a,best_b); - best_phi = 7.0; - SphereP best_c; - - for(SphereList::const_iterator it=clist.begin();it!=clist.end();++it) { - Real phi = calc_phi(temp_arc,*it,false); - if(phi>=0.0 && phi<best_phi) { - best_phi = phi; - best_c = *it; - } - } - - if(!best_c) { - LOGN_MESSAGE("singular arc detected, no reduced surface build"); - return; - } - - temp_s->pos = AxisRotation(temp_arc->axis,best_phi)* - (temp_s->pos-temp_arc->fixpoint)+ - temp_arc->fixpoint; - - // finally assemble first tet - TetP ntet(new Tet(best_a, best_b, best_c,temp_s)); - tet_list_.push_back(ntet); - // initiate the recursive traversal along the three first arcs - LOGN_DUMP("starting recursive arc traversal"); - ntet->U = ArcP(new Arc(ntet->A, ntet->B, ntet->S)); - ntet->U->A = ntet; - ntet->V = ArcP(new Arc(ntet->B, ntet->C, ntet->S)); - ntet->V->A = ntet; - ntet->W = ArcP(new Arc(ntet->C, ntet->A, ntet->S)); - ntet->W->A = ntet; - // note: creation of all three prior to traversal is necessary! - traverse_arc(ntet,ntet->U,ntet->C); - traverse_arc(ntet,ntet->V,ntet->A); - traverse_arc(ntet,ntet->W,ntet->B); - - LOGN_DUMP("build " << tet_list_.size() << " tets and " << arc_list_.size() << " arcs"); - - for(ArcList::const_iterator it=arc_list_.begin();it!=arc_list_.end();++it) { - if(!(*it)->S) LOGN_VERBOSE("invalid arc detected, null S: " << (*it)->H->name << " " << (*it)->K->name); - if(!(*it)->T) LOGN_VERBOSE("invalid arc detected, null T: " << (*it)->H->name << " " << (*it)->K->name); - } -} - -void RSurf::traverse_arc(TetP tet, ArcP& arc, SphereP c) -{ - if(tet->S!=arc->S) { - LOGN_VERBOSE("unexpected error during arc traversal: tet->S != arc->S; aborting arc traversal (" <<arc->H->name << "," << arc->K->name << ")"); - return; - } - // find the closest contact point when traversing the arc around [ab], - // away from c, and return as a tet - std::pair<TetP,bool> ret = find_best_tet(arc,c); - TetP ntet=ret.first; - - if(!ntet) { - LOGN_VERBOSE("unexpected failure during find_best_tet(); aborting arc traversal (" <<arc->H->name << "," << arc->K->name << ")"); - return; - } - - // dest tet already exists - if(ret.second) { - // grab already allocated arc from tet - ArcP narc = ntet->GetArc(arc->H,arc->K); - if(narc) { - // replace source arc with existing one - arc=narc; - // close this arc if necessary - if(!narc->T) { - narc->SetT(tet->S); - narc->B=tet; - // and add to overall list - arc_list_.push_back(narc); - } - } else { - LOGN_VERBOSE("unexpected missing arc in existing tet"); - } - - return; // existing tet: no reason to continue traversal - } - - - // given the new tet, handle current arc - ntet->U = arc; - arc->SetT(ntet->S); - arc->B=ntet; - arc_list_.push_back(arc); - - if(ntet->parity_swap) { - // B and C were swapped - ntet->V = ArcP(new Arc(ntet->C, ntet->B, ntet->S)); - ntet->V->A = ntet; - ntet->W = ArcP(new Arc(ntet->B, ntet->A, ntet->S)); - ntet->W->A = ntet; - traverse_arc(ntet,ntet->V,ntet->A); - traverse_arc(ntet,ntet->W,ntet->C); - } else { - ntet->V = ArcP(new Arc(ntet->B, ntet->C, ntet->S)); - ntet->V->A = ntet; - ntet->W = ArcP(new Arc(ntet->C, ntet->A, ntet->S)); - ntet->W->A = ntet; - traverse_arc(ntet,ntet->V,ntet->A); - traverse_arc(ntet,ntet->W,ntet->B); - } - -} - -std::pair<TetP,bool> RSurf::get_tet(SphereP a, SphereP b, SphereP c, const Sphere& s, bool create) -{ - // TODO: this could use a hash table instead of a list for faster lookup - for(TetList::const_iterator it=tet_list_.begin();it!=tet_list_.end();++it) { - Tet& tet=*(*it); - // only compare same parity - if(tet.parity_swap) { - if((tet.A==a && tet.C==b && tet.B==c) || - (tet.A==c && tet.C==a && tet.B==b) || - (tet.A==b && tet.C==c && tet.B==a)) { - return std::make_pair(*it,true); - } - } else { - if((tet.A==a && tet.B==b && tet.C==c) || - (tet.A==c && tet.B==a && tet.C==b) || - (tet.A==b && tet.B==c && tet.C==a)) { - return std::make_pair(*it,true); - } - } - } - if(create) { - TetP tet(new Tet(a,b,c,s)); - tet_list_.push_back(tet); - return std::make_pair(tet,false); - } - return std::make_pair(TetP(),false); -} - -std::pair<TetP,bool> RSurf::find_best_tet(ArcP arc, SphereP c) -{ - SphereList clist = get_nearest_spheres(arc->fixpoint,arc->H,arc->K); - Real best_phi = 7.0; - SphereP best_c; - - if(clist.empty()) { - LOGN_VERBOSE("unexpected zero length sphere list in rsurf::find_best_tet()"); - return std::make_pair(TetP(),true); - } - for(SphereList::const_iterator it=clist.begin();it!=clist.end();++it) { - Real phi = calc_phi(arc,*it,true); - if(phi<best_phi) { - if(phi<1e-8 && (*it)==c) continue; - best_phi = phi; - best_c = *it; - } - } - - if(!best_c) { - LOGN_VERBOSE("unexpected missing best_c in rsurf::find_best_tet()"); - return std::make_pair(TetP(),true); - } - - // rotate solvent around axis to get new pos - arc->phi=best_phi; - Vec3 new_pos = AxisRotation(arc->axis,best_phi)*(arc->S->pos-arc->fixpoint)+arc->fixpoint; - arc->mid = AxisRotation(arc->axis,0.5*best_phi)*(arc->S->pos-arc->fixpoint)+arc->fixpoint; - - // switch HK order for correct parity - // (actually, this is questionable and in fact verified in tet ctor) - return get_tet(arc->K,arc->H,best_c,Sphere(new_pos, probe_radius_),true); -} - -SphereList RSurf::get_nearest_spheres(const Vec3& pos, SphereP a, SphereP b) -{ - SphereList nrvo; - SpatOrg::ItemList slist = spat_org_.FindWithin(pos,2.0*(probe_radius_+max_rad_)); - for(SpatOrg::ItemList::const_iterator it=slist.begin();it!=slist.end();++it) { - if(*it!=a && *it!=b) nrvo.push_back(*it); - } - return nrvo; -} - -Real RSurf::calc_phi(ArcP arc, SphereP x, bool prune_zero) -{ - // calculate angle phi around axis given by ab, when - // starting from s at zero, and touching x upon rotating - - Vec3 p = arc->xmat*(x->pos-arc->fixpoint); - - Real r = Length(arc->S->pos-arc->fixpoint); - Real r2 = r*r; - Real x2 = p[0]*p[0]; - Real y2 = p[1]*p[1]; - Real z2 = p[2]*p[2]; - Real d = probe_radius_+x->rad; - Real d2 = d*d; - - Real phi1 = 7.0; - Real phi2 = 7.0; - - if(std::abs(p[0])<1e-8) { - - Real c4 = 1.0/(2.0*y2); - Real c5 = p[1]*(r2-d2+y2+z2); - Real ys1 = c4*c5; - - phi1 = atan2(ys1,Real(0.0)); - phi2 = phi1; - - } else { - - Real c0 = -d2+x2+y2+z2; - Real c1 = -x2*(r2*r2-2.0*r2*(d2+x2+y2-z2)+c0*c0); - if(c1<0.0) { - if(std::abs(c1)<1e-5) { - c1=0.0; - } else { - return 7.0; - } - } - c1 = sqrt(c1); - Real c2 = 1.0/(2.0*p[0]*(x2+y2)); - Real c3 = x2*(r2-d2+x2+y2+z2); - Real xs1 = c2*(c3-p[1]*c1); - Real xs2 = c2*(c3+p[1]*c1); - Real c4 = 1.0/(2.0*(x2+y2)); - Real c5 = p[1]*(r2-d2+x2+y2+z2); - Real ys1 = c4*(c5+c1); - Real ys2 = c4*(c5-c1); - - phi1 = atan2(ys1,xs1); - phi2 = atan2(ys2,xs2); - } - - if(phi1<0.0) phi1+=2.0*M_PI; - if(phi2<0.0) phi2+=2.0*M_PI; - if(prune_zero) { - if(phi1<1e-8) phi1=7.0; - if(phi2<1e-8) phi2=7.0; - } - - return std::min(phi1,phi2); -} - - -//////////////////////////////// -// Triangulation stuff -//////////////////////////////// - -namespace { - -// all helper functions are in namespace anon - -// split given list into two at position p (which is excluded) -void split_edge(const EdgePointList& in, unsigned int p, EdgePointList& o1, EdgePointList& o2) -{ - for(unsigned int i=0;i<p;++i) { - o1.push_back(in[i]); - } - for(unsigned int i=p+1;i<in.size();++i) { - o2.push_back(in[i]); - } -} - -// build edges on great arc between e1 and e2, _not_ including these two points -EdgePointList build_edge(const EdgePoint& e1, const EdgePoint& e2, - const Vec3& ori, Real patch, Real mult, - impl::SurfaceImplP& surf,int type) -{ - Vec3 d1 = e1.pos-ori; - Real rad = Length(d1); - Vec3 n1=Normalize(d1); - Vec3 n2=Normalize(e2.pos-ori); - - Vec3 ax=Normalize(Cross(n1,n2)); - Real phi=acos(Dot(n1,n2)); - int step=static_cast<int>(floor(rad*phi/patch)); - Real delta_phi=phi/static_cast<Real>(step); - - EdgePointList e12; - - for(int k=1;k<step;++k) { - Vec3 dd = AxisRotation(ax,static_cast<Real>(k)*delta_phi)*d1; - Vec3 nn = Normalize(mult*dd); - Vec3 vv = dd+ori; - e12.push_back(EdgePoint(surf->AddVertex(SurfaceVertex(vv,nn,type)),vv,nn)); - } - - return e12; -} - -// variant to above, with explicit step size -EdgePointList build_edge(const EdgePoint& e1, const EdgePoint& e2, - const Vec3& ori, int step, Real mult, - impl::SurfaceImplP& surf, int type) -{ - EdgePointList e12; - - if(step==0) return e12; - - Vec3 d1 = e1.pos-ori; - Vec3 n1=Normalize(d1); - Vec3 n2=Normalize(e2.pos-ori); - - Vec3 ax=Normalize(Cross(n1,n2)); - Real phi=acos(Dot(n1,n2)); - Real delta_phi=phi/static_cast<Real>(step); - - for(int k=1;k<step;++k) { - Vec3 dd = AxisRotation(ax,static_cast<Real>(k)*delta_phi)*d1; - Vec3 nn = Normalize(mult*dd); - Vec3 vv = dd+ori; - e12.push_back(EdgePoint(surf->AddVertex(SurfaceVertex(vv,nn,type)),vv,nn)); - } - - return e12; -} - -EdgePointList revert_epl(const EdgePointList& epl) -{ - EdgePointList nrvo(epl.size()); - std::reverse_copy(epl.begin(),epl.end(),nrvo.begin()); - return nrvo; -} - -/* - general scheme for subdivisioning - (e=corner, l=edge, p=new point, x=new edge) - - e2 - ^ /\ /\ - / /b \ x2 / \ x3 - l12 p3 /____\ p1 l23 /_x7_\ - /\ d /\ \ /\ /\ - /a \ /c \ `' x1/ x9 x8 \ x4 - / \/ \ / \/ \ - e1 ------------ e3 ------------ - p2 x6 x5 - <- l31 - - special cases are implemented when one or two - edges contain no more points -*/ - -#define SUBDIVIDE_ONEZERO(E1,E2,E3,L1,L2,L3) \ - EdgePointList x2(L2.size()-1); \ - std::copy(&L2[1],&L2[L2.size()],&x2[0]); \ - EdgePointList x3(L3.size()-1); \ - std::copy(&L3[0],&L3[L3.size()-1],&x3[0]); \ - surf->AddTri(E2.id, E1.id, L2[0].id); \ - surf->AddTri(L2[0].id, E1.id, L3.back().id); \ - subdivide(L3.back(),L2[0],E3,L1,x2,x3,ori,patch,mult,surf,type); - - -#define SUBDIVIDE_TWOZERO(E1,E2,E3,L1) \ - surf->AddTri(L1[0].id,E1.id,E3.id); \ - for(unsigned int ii=0;ii<L1.size()-1;++ii) { \ - surf->AddTri(L1[ii+1].id,L1[ii].id,E3.id); \ - } \ - surf->AddTri(E2.id,L1.back().id,E3.id); - -void subdivide(const EdgePoint& e1, const EdgePoint& e2, const EdgePoint& e3, - const EdgePointList& l12, - const EdgePointList& l23, - const EdgePointList& l31, - const Vec3& ori, Real patch, Real mult, - impl::SurfaceImplP& surf, int type) -{ - if(l12.empty() && l23.empty() && l31.empty()) { - surf->AddTri(e2.id,e1.id,e3.id); - } else if(l12.empty() && !l23.empty() && !l31.empty()) { - SUBDIVIDE_ONEZERO(e1,e2,e3,l12,l23,l31); - } else if(!l12.empty() && l23.empty() && !l31.empty()) { - SUBDIVIDE_ONEZERO(e2,e3,e1,l23,l31,l12); - } else if(!l12.empty() && !l23.empty() && l31.empty()) { - SUBDIVIDE_ONEZERO(e3,e1,e2,l31,l12,l23); - } else if(l12.empty() && l23.empty() && !l31.empty()) { - SUBDIVIDE_TWOZERO(e3,e1,e2,l31); - } else if(l12.empty() && !l23.empty() && l31.empty()) { - SUBDIVIDE_TWOZERO(e2,e3,e1,l23); - } else if(!l12.empty() && l23.empty() && l31.empty()) { - SUBDIVIDE_TWOZERO(e1,e2,e3,l12); - } else { - - unsigned int cp1=(l23.size()+1)/2-1; - unsigned int cp2=(l31.size()+1)/2-1; - unsigned int cp3=(l12.size()+1)/2-1; - - EdgePoint p1 = l23[cp1]; - EdgePoint p2 = l31[cp2]; - EdgePoint p3 = l12[cp3]; - - EdgePointList x1,x2,x3,x4,x5,x6; - - // new outer edges - split_edge(l12,cp3,x1,x2); - split_edge(l23,cp1,x3,x4); - split_edge(l31,cp2,x5,x6); - -#if 0 - EdgePointList x7 = build_edge(p1,p3,ori,patch,mult,surf,type); - EdgePointList x8 = build_edge(p2,p1,ori,patch,mult,surf,type); - EdgePointList x9 = build_edge(p3,p2,ori,patch,mult,surf,type); -#else - EdgePointList x7 = build_edge(p1,p3,ori,(int)((x2.size()+x3.size())/2),mult,surf,type); - EdgePointList x8 = build_edge(p2,p1,ori,(int)((x4.size()+x5.size())/2),mult,surf,type); - EdgePointList x9 = build_edge(p3,p2,ori,(int)((x1.size()+x6.size())/2),mult,surf,type); -#endif - - subdivide(e1,p3,p2,x1,x9,x6,ori,patch,mult,surf,type); - subdivide(p3,e2,p1,x2,x3,x7,ori,patch,mult,surf,type); - subdivide(p2,p1,e3,x8,x4,x5,ori,patch,mult,surf,type); - subdivide(p1,p2,p3,revert_epl(x8),revert_epl(x9),revert_epl(x7),ori,patch,mult,surf,type); - } -} - -struct EdgePointList3 { - EdgePointList l1,l2,l3; -}; - -EdgePointList3 build_patch(const Tet& tet, Real patch, Real mult, - impl::SurfaceImplP& surf) -{ - Vec3 ori=tet.S->pos; - Vec3 n1=-Normalize(tet.cA-ori); - EdgePoint e1(surf->AddVertex(SurfaceVertex(tet.cA,n1,1)),tet.cA,n1); - Vec3 n2=-Normalize(tet.cB-ori); - EdgePoint e2(surf->AddVertex(SurfaceVertex(tet.cB,n2,1)),tet.cB,n2); - Vec3 n3=-Normalize(tet.cC-ori); - EdgePoint e3(surf->AddVertex(SurfaceVertex(tet.cC,n3,1)),tet.cC,n3); - -#if 1 - EdgePointList l12 = build_edge(e1,e2,ori,(int)tet.U->step,mult,surf,1); - EdgePointList l23 = build_edge(e2,e3,ori,(int)tet.V->step,mult,surf,1); - EdgePointList l31 = build_edge(e3,e1,ori,(int)tet.W->step,mult,surf,1); -#else - EdgePointList l12 = build_edge(e1,e2,ori,patch,mult,surf,1); - EdgePointList l23 = build_edge(e2,e3,ori,patch,mult,surf,1); - EdgePointList l31 = build_edge(e3,e1,ori,patch,mult,surf,1); -#endif - - subdivide(e1,e2,e3,l12,l23,l31,ori,patch,mult,surf,1); - - l12.insert(l12.begin(),e1); - l12.push_back(e2); - l23.insert(l23.begin(),e2); - l23.push_back(e3); - l31.insert(l31.begin(),e3); - l31.push_back(e1); - - EdgePointList3 epl3={l12,l23,l31}; - return epl3; -} - -void build_saddle(ArcP& arcp, Real patch, impl::SurfaceImplP& surf) -{ - Arc& arc = *arcp; - if(arc.eplS.empty() || arc.eplT.empty()) { - LOGN_VERBOSE("unexpected empty arc EdgePointList"); - return; - } - if(arc.eplS.size()!=arc.eplT.size()) { - LOGN_VERBOSE("unexpected size missmatch in arc EdgePointLists (" << arc.H->name << "," << arc.K->name << ")"); - return; - } - - std::vector<EdgePointList> epll(arc.eplS.size()); - - int step=static_cast<int>(floor(arc.H->rad*arc.phi/patch)); - Real delta_phi = arc.phi/static_cast<Real>(step); - - // initialize first component of each convex running edge list - // is equivalent to step zero - for(unsigned int k=0;k<arc.eplS.size();++k) { - epll[k].push_back(arc.eplS[k]); - } - - // outer loop goes over the convex part of saddle - for(int c=1;c<step;++c) { - Mat3 vmat=AxisRotation(arc.axis,static_cast<Real>(c)*delta_phi); - // inner loop goes over concave part - for(unsigned int k=0;k<arc.eplS.size();++k) { - // this is the direction vector which is rotated around the arc axis - Vec3 p0 = arc.eplS[k].pos-arc.fixpoint; - Vec3 p1 = vmat*p0+arc.fixpoint; - // the normal is retrieved from a previous calculation - Vec3 n1 = vmat*arc.eplS[k].norm; - epll[k].push_back(EdgePoint(surf->AddVertex(SurfaceVertex(p1,n1,2)),p1,n1)); - } - } - - // this should be equivalent to the above rotation for c==step... - for(unsigned int k=0;k<arc.eplS.size();++k) { - epll[k].push_back(arc.eplT[k]); - } - - // now that all vertices are created, assign triangles - for(unsigned int k=0;k<arc.eplS.size()-1;++k) { - for(unsigned int c=0;c<epll[k].size()-1;++c) { - surf->AddTri(epll[k+1][c+1].id, - epll[k][c+1].id, - epll[k][c].id); - surf->AddTri(epll[k+1][c].id, - epll[k+1][c+1].id, - epll[k][c].id); - } - } - - // book-keeping for the spheres - ArcDirEntry adeH,adeK; - adeH.v=arc.eplS.front(); - adeH.w=arc.eplT.front(); - adeH.arc=arcp; - adeH.inv_arc=false; - adeK.v=arc.eplT.back(); - adeK.w=arc.eplS.back(); - adeK.arc=arcp; - adeK.inv_arc=true; - for(int c=0;c<step;++c) { - adeH.epl.push_back(epll.front()[c]); - adeK.epl.push_back(epll.back()[step-c-1]); - } - - arc.H->arc_list.push_back(adeH); - arc.K->arc_list.push_back(adeK); -} - -void fix_arc_list(ArcDirDeque& elist) -{ - for(uint a=0;a<elist.size()-1;++a) { - for(uint b=a+1;b<elist.size();++b) { - if(elist[a].v.id != elist[b].v.id) { - if(Length(elist[a].v.pos-elist[b].v.pos)<1.0e-4) { - elist[b].v.id = elist[a].v.id; - } - } - if(elist[a].v.id != elist[b].w.id) { - if(Length(elist[a].v.pos-elist[b].w.pos)<1.0e-4) { - elist[b].w.id = elist[a].v.id; - } - } - if(elist[a].w.id != elist[b].v.id) { - if(Length(elist[a].w.pos-elist[b].v.pos)<1.0e-4) { - elist[b].v.id = elist[a].w.id; - } - } - if(elist[a].w.id != elist[b].w.id) { - if(Length(elist[a].w.pos-elist[b].w.pos)<1.0e-4) { - elist[b].w.id = elist[a].w.id; - } - } - } - } -} - - -std::vector<ArcDirDeque> sort_arc_list(ArcDirDeque arc_list, - std::vector<Vec3>& topsumlist, - Sphere& sp) -{ - std::vector<ArcDirDeque> elistlist; - while(!arc_list.empty()) { - bool used=false; - for(ArcDirDeque::iterator ait=arc_list.begin();ait!=arc_list.end();++ait) { - for(uint l=0;l<elistlist.size();++l) { - if(ait->v.id == elistlist[l].back().w.id) { - elistlist[l].push_back(*ait); - arc_list.erase(ait); - used=true; - } else if(ait->w.id == elistlist[l].front().v.id) { - elistlist[l].push_front(*ait); - arc_list.erase(ait); - used=true; - } - if(used) { - topsumlist[l]+=(ait->arc->mid-sp.pos)*ait->arc->phi; - break; - } - } - if(used) break; - } - if(!used) { - elistlist.push_back(ArcDirDeque()); - elistlist.back().push_back(arc_list.back()); - topsumlist.push_back((arc_list.back().arc->mid-sp.pos)*arc_list.back().arc->phi); - arc_list.pop_back(); - } - } - return elistlist; -} - - -struct PolarMap -{ - struct Entry { - Real theta, phi; - uint id; - }; - - typedef std::vector<Entry> EntryList; - - PolarMap(): theta_off(0.0), phi_off(0.0) {} - void Add(const Vec3& v, uint id) { - Real l = Length(v); - Real theta=atan2(v[0],v[2]); - Real phi=acos(v[1]/l); - Real theta1=theta+theta_off; - Real phi1=phi+phi_off; - - if(!entry_list.empty()) { - Real theta0=entry_list.back().theta; - Real phi0=entry_list.back().phi; - - /*Real theta2=theta1; - Real phi2=phi1;*/ - if(theta1-theta0>M_PI) { - theta1-=2.0*M_PI; - theta_off=-2.0*M_PI; - } else if(theta1-theta0<-M_PI) { - theta1+=2.0*M_PI; - theta_off+=2.0*M_PI; - } - if(phi1-phi0>M_PI_2) { - phi1-=M_PI; - phi_off=-M_PI; - } else if(phi1-phi0<-M_PI_2) { - phi1+=M_PI; - phi_off+=M_PI; - } - - theta_min=std::min(theta_min,theta1); - theta_max=std::max(theta_max,theta1); - phi_min=std::min(phi_min,phi1); - phi_max=std::max(phi_max,phi1); - - } else { - theta_min=theta1; - theta_max=theta1; - phi_min=phi1; - phi_max=phi1; - } - Entry e={theta1,phi1,id}; - entry_list.push_back(e); - } - - Real theta_off,phi_off; - Real theta_min,theta_max; - Real phi_min,phi_max; - EntryList entry_list; -}; - -struct CapEdgeEntry { - CapEdgeEntry() {} - CapEdgeEntry(uint i, Real t, Real p): eid(i), theta(t), phi(p) {} - uint eid; - Real theta, phi; -}; - -typedef std::vector<CapEdgeEntry> CapEdgeList; - -struct CapVecEntry { -}; - -typedef std::vector<CapVecEntry> CapVecList; - -void build_cap(Sphere& sp, Real patch, impl::SurfaceImplP& surf) -{ - // assemble sorted lists of spheres and edge-point-lists - std::vector<Vec3> topsumlist; - std::vector<ArcDirDeque> alistlist = sort_arc_list(sp.arc_list,topsumlist,sp); - - sp.arc_list_list=alistlist; - - bool check=true; - // for each independent list, build cap - for(uint l=0;l<alistlist.size();++l) { - ArcDirDeque& alist = alistlist[l]; - if(alist.front().v.id != alist.back().w.id) { - check=false; - break; - } - } - if(!check) { - LOGN_DEBUG("non-circular arc-dir list found, attempting fix"); - ArcDirDeque tmp_list=sp.arc_list; - fix_arc_list(tmp_list); - topsumlist.clear(); - alistlist = sort_arc_list(tmp_list,topsumlist,sp); - sp.arc_list_list=alistlist; - } - - sp.top_list.resize(alistlist.size()); - - std::vector<Vec3> vlist; - std::vector<uint> ilist; - build_sphere(4,vlist,ilist); - - for(uint l=0;l<alistlist.size();++l) { - ArcDirDeque& alist = alistlist[l]; - if(alist.front().v.id != alist.back().w.id) { - LOGN_VERBOSE("unexpected non-circular arc-dir list for [" << sp.name << "]"); - continue; - } - - // generate the top position - Vec3 sum1; - Vec3 sum2; - Vec3 prev; - float plan=0.0; - for(uint i=0;i<alist.size();++i) { - uint j = (i-1+alist.size())%alist.size(); - uint k = (i+1)%alist.size(); - sum1+=(alist[i].arc->mid-sp.pos)*alist[i].arc->phi; - Vec3 d0 = alist[i].arc->S->pos-sp.pos; - Vec3 d1 = alist[i].arc->mid-sp.pos; - Vec3 d2 = alist[i].arc->T->pos-sp.pos; - - Vec3 p0 = sp.pos+sp.rad*(d0)/(sp.rad+alist[i].arc->S->rad); - Vec3 p1 = sp.pos+sp.rad*(d1)/(sp.rad+alist[i].arc->S->rad); - Vec3 p2 = sp.pos+sp.rad*(d2)/(sp.rad+alist[i].arc->S->rad); - Vec3 c0 = Normalize(Cross(Normalize(alist[i].w.pos-alist[i].v.pos), - Normalize(alist[k].w.pos-alist[k].v.pos))+ - Cross(Normalize(alist[j].w.pos-alist[j].v.pos), - Normalize(alist[i].w.pos-alist[i].v.pos))); - if(i>0) { - plan+=Dot(prev,Normalize(d1)); - } - prev=Normalize(d1); - sum2+=c0*alist[i].arc->phi; - } - Real f = plan/static_cast<Real>(alist.size()); - // this is a combination of two algorithms, weighted by planarity - Vec3 topn = Normalize(f*sum1+(1.0-f)*sum2); - Vec3 topv = sp.pos+sp.rad*topn; - - sp.top_list[l]=topv; - - // now for the actual cap - - PolarMap polar_map; - for(ArcDirDeque::const_iterator ait=alist.begin();ait!=alist.end();++ait) { - std::cerr << ait->v.id << std::endl; - for(EdgePointList::const_iterator eit=ait->epl.begin();eit!=ait->epl.end();++eit) { - polar_map.Add(eit->pos-sp.pos,eit->id); - } - } - if(polar_map.entry_list.empty()) continue; - polar_map.entry_list.push_back(polar_map.entry_list.front()); - - for(uint i=0;i<polar_map.entry_list.size();++i) { - PolarMap::Entry& e = polar_map.entry_list[i]; - std::cerr << i+1 << " " << (e.theta-polar_map.theta_min)*57.3 << " " << (e.phi+(M_PI-polar_map.phi_max))*57.3 << std::endl; - } - - } -} - -} // ns - -void RSurf::Triangulate(impl::SurfaceImplP& surface, Real patch_size) -{ - for(ArcList::iterator it=arc_list_.begin();it!=arc_list_.end();++it) { - Arc& arc = *(*it); - Real da=arc.H->rad+probe_radius_; - Real db=arc.K->rad+probe_radius_; - Real dc=Length(arc.H->pos-arc.K->pos); - Real cosphi = -0.5*(dc*dc-da*da-db*db)/(da*db); - cosphi = std::min(Real(1.0),std::max(Real(-1.0),cosphi)); - arc.step = static_cast<int>(floor(acos(cosphi)*probe_radius_/patch_size)); - } - - for(TetList::const_iterator it=tet_list_.begin();it!=tet_list_.end();++it) { - Tet& tet=*(*it); - // make S sphere concave patch - EdgePointList3 epl3=build_patch(tet, patch_size, -1.0, surface); - - // assign stored edgepointlists - if(tet.U->S==tet.S) { - tet.U->eplS=epl3.l1; - } else if(tet.U->T==tet.S) { - tet.U->eplT=revert_epl(epl3.l1); - } - if(tet.V->S==tet.S) { - tet.V->eplS=epl3.l2; - } else if(tet.V->T==tet.S) { - tet.V->eplT=revert_epl(epl3.l2); - } - if(tet.W->S==tet.S) { - tet.W->eplS=epl3.l3; - } else if(tet.W->T==tet.S) { - tet.W->eplT=revert_epl(epl3.l3); - } - } - - for(ArcList::iterator it=arc_list_.begin();it!=arc_list_.end();++it) { - build_saddle(*it,patch_size,surface); - } - - for(SphereList::const_iterator it=sphere_list_.begin();it!=sphere_list_.end();++it) { - if((*it)->arc_list.empty()) continue; - build_cap(*(*it),patch_size,surface); - } - - std::vector<SurfaceVertexID> vlist = surface->GetVertexIDList(); - std::vector<SurfaceTriID> tlist = surface->GetTriIDList(); - LOGN_VERBOSE("added " << vlist.size() << " vertices and " << tlist.size() << " tris"); -} - - -}}} // ns diff --git a/modules/mol/base/src/impl/rsurf_impl.hh b/modules/mol/base/src/impl/rsurf_impl.hh deleted file mode 100644 index 5f7755afeebde926f9057c3aec6d25ec72e6d276..0000000000000000000000000000000000000000 --- a/modules/mol/base/src/impl/rsurf_impl.hh +++ /dev/null @@ -1,207 +0,0 @@ -//------------------------------------------------------------------------------ -// This file is part of the OpenStructure project <www.openstructure.org> -// -// Copyright (C) 2008-2010 by the OpenStructure authors -// -// This library is free software; you can redistribute it and/or modify it under -// the terms of the GNU Lesser General Public License as published by the Free -// Software Foundation; either version 3.0 of the License, or (at your option) -// any later version. -// This library is distributed in the hope that it will be useful, but WITHOUT -// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -// details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this library; if not, write to the Free Software Foundation, Inc., -// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -//------------------------------------------------------------------------------ -#ifndef OST_SURFACE_IMPL_RSURF_HH -#define OST_SURFACE_IMPL_RSURF_HH - -/* - A fast reduced surface implementation to generate molecular surfaces - - The concept of a reduced surface was introduced by M Sanner et al, 1984 - - Author: Ansgar Philippsen -*/ - -#include <vector> -#include <deque> - -#include <boost/shared_ptr.hpp> - -#include <ost/geom/geom.hh> -#include <ost/mol/spatial_organizer.hh> -#include "surface_impl_fw.hh" -#include <ost/mol/surface_prop.hh> - -namespace ost { namespace mol { namespace rsurf { - -// helper types for triangulation -// \internal -struct EdgePoint -{ - EdgePoint(): id(0),pos() {} - EdgePoint(SurfaceVertexID i, const geom::Vec3& p, const geom::Vec3& n): - id(i), pos(p), norm(n) {} - SurfaceVertexID id; - geom::Vec3 pos,norm; -}; - -/// \internal -typedef std::vector<EdgePoint> EdgePointList; - -// required before sphere -/// \internal -struct Arc; - -/// \internal -typedef boost::shared_ptr<Arc> ArcP; - -/// \internal -typedef std::vector<ArcP> ArcList; - -/// \internal -struct ArcDirEntry { - EdgePointList epl; - EdgePoint v,w; - ArcP arc; - bool inv_arc; -}; - -/// \internal -typedef std::deque<ArcDirEntry> ArcDirDeque; - -// basic sphere -struct Sphere { - Sphere(const geom::Vec3& p, Real r): pos(p), rad(r) {} - geom::Vec3 pos; - Real rad; - String name; - ArcDirDeque arc_list; - std::vector<geom::Vec3> top_list; - std::vector<ArcDirDeque> arc_list_list; -}; - -typedef boost::shared_ptr<Sphere> SphereP; -typedef std::vector<SphereP> SphereList; - -struct Tet; -typedef boost::shared_ptr<Tet> TetP; - - -// arc that bridges two tets -/* - the orientation of H,K,S,T is such that the rotation of S - around the HK axis towards T is positive right handed: - - S T (S is in front, T in back) - \/ - K----H - - i.e. for HK=Vec3(0,0,1) and S=Vec3(1,0,0), a 90deg - positive rotation results in Vec3(0,1,0) - -*/ -struct Arc { - Arc(); - Arc(const SphereP& h, const SphereP& k, const SphereP& s); - void SetT(const SphereP& t); - - SphereP H,K; // the two sphere that form the axis - SphereP S,T; // the start and end solvent sphere - geom::Vec3 axis; // normalized axis from H to K - geom::Vec3 fixpoint; // point on axis where sdir and tdir start - geom::Vec3 sdir; // direction normal from axis to S - geom::Vec3 tdir; // direction normal from axis to T - Real phi; // angle from S to T - geom::Mat3 xmat; // transformation matrix needed during traversal - geom::Vec3 mid; - EdgePointList eplS, eplT; // book-keeping for the triangulation - TetP A,B; - uint step; // sync edge stepsize for triangulation -}; - - -// the constellation of three spheres with a locked solvent sphere -/* - when viewed with the solvent sphere in front of the abc triplet, - [ABC] are arranged clockwise -*/ -struct Tet { - // use already determined sphere - Tet(const SphereP& a, const SphereP& b, const SphereP& c, const Sphere& s); - // use existing S - Tet(const SphereP& a, const SphereP& b, const SphereP& c, const SphereP& s); - - ArcP GetArc(const SphereP& h, const SphereP& k); - - SphereP A,B,C,S; - ArcP U,V,W; - - geom::Vec3 cA,cB,cC; // contact points of S with A,B and C - - bool parity_swap; - - void init(); -}; - -typedef std::vector<TetP> TetList; - -// spatial organizer for optimized search -typedef SpatialOrganizer<SphereP> SpatOrg; - -class DLLEXPORT_OST_MOL RSurf -{ -public: - // ctor - RSurf(Real probe_radius); - - void AddSphere(const geom::Vec3& pos, Real rad, const String& name); - - // construct reduced surface from spheres - void Build(); - - // triangulate rsurf and thereby build full molecular surface - void Triangulate(impl::SurfaceImplP& surface, Real patch_size); - - // return probe radius - Real GetProbeRadius() const {return probe_radius_;} - - // internal use - ArcList GetArcList() const {return arc_list_;} - // internal use - TetList GetTetList() const {return tet_list_;} - // internal use - SphereList GetSphereList() const {return sphere_list_;} - -private: - - // main recursive routine - void traverse_arc(TetP tet, ArcP& arc, SphereP c); - - // get tet from list, optionally creating it if necessary - // the solvent s is either used as a parity check, or as the new sphere - std::pair<TetP,bool> get_tet(SphereP a, SphereP b, SphereP c, const Sphere& s, bool create); - - // find best tet for an arc traversal - std::pair<TetP,bool> find_best_tet(ArcP arc, SphereP c); - - SphereList get_nearest_spheres(const geom::Vec3& pos, SphereP a, SphereP b); - - Real calc_phi(ArcP arc, SphereP x, bool prune_zero); - - SphereList sphere_list_; - ArcList arc_list_; - TetList tet_list_; - Real probe_radius_; - Real max_rad_; - SpatOrg spat_org_; -}; - - -}}} // ns - -#endif diff --git a/modules/mol/base/src/impl/surface_impl.hh b/modules/mol/base/src/impl/surface_impl.hh index 4a577806ca439cefd1d40616451fd66412b766c4..78fd1ea57e26f6c725647beeb4fbfa5d74da44f0 100644 --- a/modules/mol/base/src/impl/surface_impl.hh +++ b/modules/mol/base/src/impl/surface_impl.hh @@ -37,8 +37,6 @@ class DLLEXPORT_OST_MOL SurfaceImpl { typedef std::vector<SurfaceVertex> VertexList; typedef std::vector<SurfaceTri> FaceList; - friend class ::ost::mol::rsurf::RSurf; - public: SurfaceImpl(); diff --git a/modules/mol/base/src/impl/surface_impl_fw.hh b/modules/mol/base/src/impl/surface_impl_fw.hh index c5b9007b5c004ea7758ca77449aa41bd8ff91efc..dac23ce7456074662dde55f554b278d8302af26a 100644 --- a/modules/mol/base/src/impl/surface_impl_fw.hh +++ b/modules/mol/base/src/impl/surface_impl_fw.hh @@ -28,14 +28,4 @@ typedef boost::shared_ptr<SurfaceImpl> SurfaceImplP; }}} // ns -namespace ost { namespace mol { namespace rsurf { - -/// \internal -class RSurf; - -/// \internal -typedef boost::shared_ptr<RSurf> RSurfP; - -}}} // ns - #endif diff --git a/modules/mol/base/src/iterator.cc b/modules/mol/base/src/iterator.cc index 26fc516444fcfc4000b66f75da3e4d2021dd5ff8..74ff90c6514b1fd86517d68aba1ceddfd604694c 100644 --- a/modules/mol/base/src/iterator.cc +++ b/modules/mol/base/src/iterator.cc @@ -28,21 +28,21 @@ namespace ost { namespace mol { ResidueHandleIter& ResidueHandleIter::operator++() { ++cur_res_; - if (cur_res_==cur_chain_->second->GetResidueList().end()) { + if (cur_res_==(*cur_chain_)->GetResidueList().end()) { // we have to skip over empty chains otherwise we end up pointing to an // invalid residue. do { ++cur_chain_; - if (ent_->GetChainMap().end()==cur_chain_) { + if (ent_->GetChainList().end()==cur_chain_) { break; } - cur_res_=cur_chain_->second->GetResidueList().begin(); - } while (cur_chain_->second->GetResidueList().empty()); + cur_res_=(*cur_chain_)->GetResidueList().begin(); + } while ((*cur_chain_)->GetResidueList().empty()); } return *this; } -ResidueHandleIter::ResidueHandleIter(impl::ChainImplMap::iterator chain_it, +ResidueHandleIter::ResidueHandleIter(impl::ChainImplList::iterator chain_it, impl::ResidueImplList::iterator res_it, impl::EntityImplPtr ent) : cur_chain_(chain_it), cur_res_(res_it), @@ -99,7 +99,7 @@ AtomHandleIter::AtomHandleIter() #endif {} -AtomHandleIter::AtomHandleIter(impl::ChainImplMap::iterator chain_it, +AtomHandleIter::AtomHandleIter(impl::ChainImplList::iterator chain_it, impl::ResidueImplList::iterator res_it, impl::AtomImplList::iterator atom_it, impl::EntityImplPtr ent, bool skip_empty) @@ -122,19 +122,19 @@ void AtomHandleIter::SkipEmpty() // pointing to an invalid atom. do { ++cur_res_; - if (cur_chain_->second->GetResidueList().end()==cur_res_) { + if ((*cur_chain_)->GetResidueList().end()==cur_res_) { do { ++cur_chain_; - if (ent_->GetChainMap().end()==cur_chain_) { + if (ent_->GetChainList().end()==cur_chain_) { return; } - cur_res_=cur_chain_->second->GetResidueList().begin(); - if (!cur_chain_->second->GetResidueList().empty()) + cur_res_=(*cur_chain_)->GetResidueList().begin(); + if (!(*cur_chain_)->GetResidueList().empty()) cur_atom_=(*cur_res_)->GetAtomList().begin(); else cur_atom_=impl::AtomImplList::iterator(); - } while (cur_chain_->second->GetResidueList().empty()); + } while ((*cur_chain_)->GetResidueList().empty()); } else { cur_atom_=(*cur_res_)->GetAtomList().begin(); } diff --git a/modules/mol/base/src/iterator.hh b/modules/mol/base/src/iterator.hh index 4d75aec8b05e7245a2d382ee96ae51e5f5406c7e..7bbbe48396591eea4ba1af3f8fc991976b754dec 100644 --- a/modules/mol/base/src/iterator.hh +++ b/modules/mol/base/src/iterator.hh @@ -80,17 +80,17 @@ private: namespace impl { // forward declearation of chain impl map. - typedef std::map<String, ChainImplPtr> ChainImplMap; + typedef std::vector<ChainImplPtr> ChainImplList; } class DLLEXPORT_OST_MOL ChainHandleIter : public std::iterator<std::forward_iterator_tag, ChainHandle> { public: // internally used constructors - ChainHandleIter(impl::ChainImplMap::iterator chain_it) + ChainHandleIter(impl::ChainImplList::iterator chain_it) : cur_(chain_it) { } public: ChainHandle operator*() { - return ChainHandle(cur_->second); + return ChainHandle(*cur_); } ChainHandleIter& operator++() { @@ -106,7 +106,7 @@ public: return !this->operator==(rhs); } private: - impl::ChainImplMap::iterator cur_; + impl::ChainImplList::iterator cur_; }; class DLLEXPORT_OST_MOL ResidueHandleIter : public std::iterator<std::forward_iterator_tag, @@ -114,7 +114,7 @@ class DLLEXPORT_OST_MOL ResidueHandleIter : public std::iterator<std::forward_it public: ResidueHandleIter() { } - ResidueHandleIter(impl::ChainImplMap::iterator chain_it, + ResidueHandleIter(impl::ChainImplList::iterator chain_it, impl::ResidueImplList::iterator res_it, impl::EntityImplPtr ent); bool operator==(const ResidueHandleIter& rhs) const { @@ -133,7 +133,7 @@ public: ResidueHandle operator*(); private: - impl::ChainImplMap::iterator cur_chain_; + impl::ChainImplList::iterator cur_chain_; impl::ResidueImplList::iterator cur_res_; impl::EntityImplPtr ent_; }; @@ -174,7 +174,7 @@ class DLLEXPORT_OST_MOL AtomHandleIter : public std::iterator<std::forward_itera public: AtomHandleIter(); - AtomHandleIter(impl::ChainImplMap::iterator chain_it, + AtomHandleIter(impl::ChainImplList::iterator chain_it, impl::ResidueImplList::iterator res_it, impl::AtomImplList::iterator atom_it, impl::EntityImplPtr ent, bool skip_empty); @@ -195,7 +195,7 @@ public: AtomHandle operator*(); private: void SkipEmpty(); - impl::ChainImplMap::iterator cur_chain_; + impl::ChainImplList::iterator cur_chain_; impl::ResidueImplList::iterator cur_res_; impl::AtomImplList::iterator cur_atom_; impl::EntityImplPtr ent_; diff --git a/modules/mol/base/src/residue_handle.cc b/modules/mol/base/src/residue_handle.cc index b66c83250276d6301b4c9699c1f72483e1a70c8f..bfc57c1949c209f753e0592730669f82f179c020 100644 --- a/modules/mol/base/src/residue_handle.cc +++ b/modules/mol/base/src/residue_handle.cc @@ -181,7 +181,7 @@ AtomHandleIter ResidueHandle::AtomsBegin() const impl::ResidueImplPtr r=Impl(); int index=this->GetIndex(); impl::ChainImplPtr c=r->GetChain(); - impl::ChainImplMap::iterator cc=r->GetEntity()->GetChainMap().find(c->GetName()); + impl::ChainImplList::iterator cc=r->GetEntity()->GetChain(c->GetName()); return AtomHandleIter(cc, c->GetResidueList().begin()+index, r->GetAtomList().begin(), r->GetEntity(), true); } @@ -192,7 +192,7 @@ AtomHandleIter ResidueHandle::AtomsEnd() const impl::ResidueImplPtr r=Impl(); int index=this->GetIndex(); impl::ChainImplPtr c=r->GetChain(); - impl::ChainImplMap::iterator cc=r->GetEntity()->GetChainMap().find(c->GetName()); + impl::ChainImplList::iterator cc=r->GetEntity()->GetChain(c->GetName()); if (c->GetResidueList().begin()+index+1==c->GetResidueList().end()) { return AtomHandleIter(cc, c->GetResidueList().begin()+index, r->GetAtomList().end(), r->GetEntity(), false); diff --git a/modules/mol/base/src/residue_view.cc b/modules/mol/base/src/residue_view.cc index b9cc9b8b78bf48cb85e1db9e9dcce38f027ae429..72c5ff76fbd08034f744229f76c24e975ba4ee1d 100644 --- a/modules/mol/base/src/residue_view.cc +++ b/modules/mol/base/src/residue_view.cc @@ -208,9 +208,9 @@ double ResidueView::GetMass() const geom::Vec3 ResidueView::GetGeometricStart() const { this->CheckValidity(); - geom::Vec3 minimum(std::numeric_limits<double>::max(), - std::numeric_limits<double>::max(), - std::numeric_limits<double>::max()); + geom::Vec3 minimum(std::numeric_limits<Real>::max(), + std::numeric_limits<Real>::max(), + std::numeric_limits<Real>::max()); AtomViewList::const_iterator i; for (i=data_->atoms.begin(); i!=data_->atoms.end(); ++i) { minimum=geom::Min(minimum, (*i).GetPos()); @@ -221,9 +221,9 @@ geom::Vec3 ResidueView::GetGeometricStart() const geom::Vec3 ResidueView::GetGeometricEnd() const { this->CheckValidity(); - geom::Vec3 maximum(-std::numeric_limits<double>::max(), - -std::numeric_limits<double>::max(), - -std::numeric_limits<double>::max()); + geom::Vec3 maximum(-std::numeric_limits<Real>::max(), + -std::numeric_limits<Real>::max(), + -std::numeric_limits<Real>::max()); AtomViewList::const_iterator i; for (i=data_->atoms.begin(); i!=data_->atoms.end(); ++i) { maximum=geom::Max(maximum, (*i).GetPos()); diff --git a/modules/mol/base/src/surface.hh b/modules/mol/base/src/surface.hh index 5e9e848d307e81ec465c684558407566ed94997c..97e1bacec719d6cada06910a3b1f16065831f926 100644 --- a/modules/mol/base/src/surface.hh +++ b/modules/mol/base/src/surface.hh @@ -21,6 +21,5 @@ #include <ost/mol/surface_handle.hh> #include <ost/mol/impl/surface_impl.hh> -#include <ost/mol/impl/rsurf_impl.hh> #endif diff --git a/modules/mol/base/src/surface_builder.cc b/modules/mol/base/src/surface_builder.cc index 75214f3de4d24f215c1d93ac7260fa97f7422d49..4fd1a97e4c3610c492fedb4c58bd2a4ed7819b8e 100644 --- a/modules/mol/base/src/surface_builder.cc +++ b/modules/mol/base/src/surface_builder.cc @@ -18,10 +18,9 @@ //------------------------------------------------------------------------------ #include "surface_builder.hh" -#include "surface_handle.hh" -#include <ost/mol/impl/surface_impl.hh> -#include <ost/mol/impl/rsurf_impl.hh> +#include <ost/log.hh> +#include "surface_handle.hh" #include "entity_view.hh" #include "iterator.hh" @@ -29,18 +28,8 @@ namespace ost { namespace mol { SurfaceHandle BuildSurface(const EntityView& ev, Real probe_radius, Real patch_size) { - rsurf::RSurf rsurf(probe_radius); - - for(AtomViewIter it=ev.AtomsBegin();it!=ev.AtomsEnd();++it) { - rsurf.AddSphere((*it).GetPos(),(*it).GetAtomProps().radius,(*it).GetQualifiedName()); - } - - rsurf.Build(); - - impl::SurfaceImplP impl(new impl::SurfaceImpl()); - rsurf.Triangulate(impl,patch_size); - - return SurfaceHandle(impl); + LOGN_ERROR("not yet implemented"); + return SurfaceHandle(); } }} diff --git a/modules/mol/base/src/surface_handle.cc b/modules/mol/base/src/surface_handle.cc index 06f920b8810112f89fac63e7a97cb378e46700ca..6d1e82e643e3ff36d5d2a4d78803bb3ed42eb29a 100644 --- a/modules/mol/base/src/surface_handle.cc +++ b/modules/mol/base/src/surface_handle.cc @@ -28,6 +28,10 @@ SurfaceHandle CreateSurface() } +SurfaceHandle::SurfaceHandle(): + impl_() +{} + SurfaceHandle::SurfaceHandle(const impl::SurfaceImplP& p): impl_(p) {} diff --git a/modules/mol/base/src/surface_handle.hh b/modules/mol/base/src/surface_handle.hh index 1802afd5b9c4286e23cd859aa60a61527dca6b78..bfc48f5e0780db7ba3b04ec0a120346a3d9cb952 100644 --- a/modules/mol/base/src/surface_handle.hh +++ b/modules/mol/base/src/surface_handle.hh @@ -38,6 +38,9 @@ typedef std::vector<SurfaceVertexID> SurfaceVertexIDList; // molecular surface class DLLEXPORT_OST_MOL SurfaceHandle { public: + // creates invalid handle + SurfaceHandle(); + // internally used ctor SurfaceHandle(const impl::SurfaceImplP& p); diff --git a/modules/mol/base/tests/test_view.cc b/modules/mol/base/tests/test_view.cc index 33bda815dc7a85e6039bd3dcf4d93b33db7777c7..26399e10e1c240182d87f59a453a605d69dd3902 100644 --- a/modules/mol/base/tests/test_view.cc +++ b/modules/mol/base/tests/test_view.cc @@ -77,6 +77,17 @@ BOOST_AUTO_TEST_CASE(gen_full_view) BOOST_CHECK_EQUAL(avl[1].GetBondCount(),2); BOOST_CHECK_EQUAL(avl[2].GetBondCount(),2); BOOST_CHECK_EQUAL(avl[3].GetBondCount(),1); + + mol::AtomView av1=avl[0]; + mol::AtomView av2=avl[1]; + + BOOST_CHECK(av1!=av2); + BOOST_CHECK(av1.GetHashCode()!=av2.GetHashCode()); + BOOST_CHECK(av1.GetHandle().GetHashCode()!=av1.GetHashCode()); + + mol::AtomView av3=av1; + BOOST_CHECK(av1==av3); + BOOST_CHECK_EQUAL(av1.GetHashCode(), av3.GetHashCode()); } BOOST_AUTO_TEST_SUITE_END() diff --git a/modules/qa/src/index.hh b/modules/qa/src/index.hh index 2f67aea956935b8c124ac63286bf12baa4c1dfed..f2744aa2632e9a89bab48208fda051717a7d9482 100644 --- a/modules/qa/src/index.hh +++ b/modules/qa/src/index.hh @@ -40,7 +40,7 @@ public: memcpy(data_, rhs.data_, sizeof(uint32_t[D])); } IndexBase() { - memset(data_, sizeof(uint32_t[D]), 0); + memset(data_, 0, sizeof(uint32_t[D])); } IndexBase& operator=(const IndexBase& rhs) { memcpy(data_, rhs.data_, sizeof(uint32_t[D])); diff --git a/modules/seq/alg/pymod/CMakeLists.txt b/modules/seq/alg/pymod/CMakeLists.txt index 22db6f7e887e1b848458c47a004383ae5767d956..93dd1b348e19c104bc5364eb04dbde4238bd5dfa 100644 --- a/modules/seq/alg/pymod/CMakeLists.txt +++ b/modules/seq/alg/pymod/CMakeLists.txt @@ -5,4 +5,4 @@ set(OST_SEQ_ALG_PYMOD_SOURCES pymod(NAME seq_alg OUTPUT_DIR ost/seq/alg CPP ${OST_SEQ_ALG_PYMOD_SOURCES} - PY __init__.py) + PY __init__.py mat.py) diff --git a/modules/seq/alg/pymod/__init__.py b/modules/seq/alg/pymod/__init__.py index 22aa0c8632d507f99b0d8943b0a102a94ecedce2..5d4730f17b92b7eed13cf47fe02d802e3267364b 100644 --- a/modules/seq/alg/pymod/__init__.py +++ b/modules/seq/alg/pymod/__init__.py @@ -1 +1,5 @@ -from _seq_alg import * \ No newline at end of file +from _seq_alg import * +from ost.seq.alg.mat import * + + + \ No newline at end of file diff --git a/modules/seq/alg/pymod/mat.py b/modules/seq/alg/pymod/mat.py new file mode 100644 index 0000000000000000000000000000000000000000..65152f045bf70ef2c50568b3abcbcfd526f38294 --- /dev/null +++ b/modules/seq/alg/pymod/mat.py @@ -0,0 +1,45 @@ +from ost.seq.alg import SubstWeightMatrix + +def _InitMatrix(data): + """ + Initialise a new substitution weight matrix with the weights in data. data + must be a 24x24 array of ints. + """ + mat=SubstWeightMatrix() + # string of valid amino acid one letter codes + chars='ABCDEFGHIKLMNPQRSTVWXYZ' + for i, row in enumerate(data): + for j, weight in enumerate(row): + mat.SetWeight(chars[i], chars[j], weight) + return mat + + +_RAW_BLOSUM62_DATA=( + (4,-2,0,-2,-1,-2,0,-2,-1,-1,-1,-1,-2,-1,-1,-1,1,0,0,-3,-1,-2), + (-2,6,-3,6,2,-3,-1,-1,-3,-1,-4,-3,1,-1,0,-2,0,-1,-3,-4,-1,-3), + (0,-3,9,-3,-4,-2,-3,-3,-1,-3,-1,-1,-3,-3,-3,-3,-1,-1,-1,-2,-1,-2), + (-2,6,-3,6,2,-3,-1,-1,-3,-1,-4,-3,1,-1,0,-2,0,-1,-3,-4,-1,-3), + (-1,2,-4,2,5,-3,-2,0,-3,1,-3,-2,0,-1,2,0,0,-1,-2,-3,-1,-2), + (-2,-3,-2,-3,-3,6,-3,-1,0,-3,0,0,-3,-4,-3,-3,-2,-2,-1,1,-1,3), + (0,-1,-3,-1,-2,-3,6,-2,-4,-2,-4,-3,0,-2,-2,-2,0,-2,-3,-2,-1,-3), + (-2,-1,-3,-1,0,-1,-2,8,-3,-1,-3,-2,1,-2,0,0,-1,-2,-3,-2,-1,2), + (-1,-3,-1,-3,-3,0,-4,-3,4,-3,2,1,-3,-3,-3,-3,-2,-1,3,-3,-1,-1), + (-1,-1,-3,-1,1,-3,-2,-1,-3,5,-2,-1,0,-1,1,2,0,-1,-2,-3,-1,-2), + (-1,-4,-1,-4,-3,0,-4,-3,2,-2,4,2,-3,-3,-2,-2,-2,-1,1,-2,-1,-1), + (-1,-3,-1,-3,-2,0,-3,-2,1,-1,2,5,-2,-2,0,-1,-1,-1,1,-1,-1,-1), + (-2,1,-3,1,0,-3,0,1,-3,0,-3,-2,6,-2,0,0,1,0,-3,-4,-1,-2), + (-1,-1,-3,-1,-1,-4,-2,-2,-3,-1,-3,-2,-2,7,-1,-2,-1,-1,-2,-4,-1,-3), + (-1,0,-3,0,2,-3,-2,0,-3,1,-2,0,0,-1,5,1,0,-1,-2,-2,-1,-1), + (-1,-2,-3,-2,0,-3,-2,0,-3,2,-2,-1,0,-2,1,5,-1,-1,-3,-3,-1,-2), + (1,0,-1,0,0,-2,0,-1,-2,0,-2,-1,1,-1,0,-1,4,1,-2,-3,-1,-2), + (0,-1,-1,-1,-1,-2,-2,-2,-1,-1,-1,-1,0,-1,-1,-1,1,5,0,-2,-1,-2), + (0,-3,-1,-3,-2,-1,-3,-3,3,-2,1,1,-3,-2,-2,-3,-2,0,4,-3,-1,-1), + (-3,-4,-2,-4,-3,1,-2,-2,-3,-3,-2,-1,-4,-4,-2,-3,-3,-2,-3,11,-1,2), + (-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1), + (-2,-3,-2,-3,-2,3,-3,2,-1,-2,-1,-1,-2,-3,-1,-2,-2,-2,-1,2,-1,7), + (-1,2,-4,2,5,-3,-2,0,-3,1,-3,-2,0,-1,2,0,0,-1,-2,-3,-1,-2), +) + +BLOSUM62=_InitMatrix(_RAW_BLOSUM62_DATA) + +__all__=['BLOSUM62'] \ No newline at end of file diff --git a/modules/seq/alg/pymod/wrap_seq_alg.cc b/modules/seq/alg/pymod/wrap_seq_alg.cc index d4c4462c861fdee993e124db514b39991a49d4db..561d0379c24210f86a9bee8a321f2ee7431c7723 100644 --- a/modules/seq/alg/pymod/wrap_seq_alg.cc +++ b/modules/seq/alg/pymod/wrap_seq_alg.cc @@ -22,7 +22,7 @@ #include <ost/seq/alg/merge_pairwise_alignments.hh> #include <ost/seq/alg/sequence_identity.hh> #include <ost/seq/alg/ins_del.hh> - +#include <ost/seq/alg/conservation.hh> using namespace boost::python; using namespace ost::seq; using namespace ost::seq::alg; @@ -47,5 +47,6 @@ BOOST_PYTHON_MODULE(_seq_alg) .def("GetInsertions", &InsDel::GetInsertions) ; def("MergePairwiseAlignments", &MergePairwiseAlignments); + def("Conservation", &Conservation, (arg("assign")=true, arg("prop_name")="cons")); export_Align(); } diff --git a/modules/seq/alg/src/CMakeLists.txt b/modules/seq/alg/src/CMakeLists.txt index ae43bd38d1d9bea4f7fbacd7d50be2d9eef46775..5f3cac427b7c4b20094856c135accdd854aac184 100644 --- a/modules/seq/alg/src/CMakeLists.txt +++ b/modules/seq/alg/src/CMakeLists.txt @@ -7,6 +7,7 @@ local_align.hh alignment_opts.hh global_align.hh merge_pairwise_alignments.hh +conservation.hh ) set(OST_SEQ_ALG_SOURCES @@ -16,6 +17,7 @@ sequence_identity.cc ins_del.cc subst_weight_matrix.cc local_align.cc +conservation.cc ) module(NAME seq_alg HEADER_OUTPUT_DIR ost/seq/alg SOURCES ${OST_SEQ_ALG_SOURCES} diff --git a/modules/seq/alg/src/conservation.cc b/modules/seq/alg/src/conservation.cc new file mode 100644 index 0000000000000000000000000000000000000000..e5a0df71d875a088ae8bd5863e8fa72ef5a8169f --- /dev/null +++ b/modules/seq/alg/src/conservation.cc @@ -0,0 +1,132 @@ +//------------------------------------------------------------------------------ +// This file is part of the OpenStructure project <www.openstructure.org> +// +// Copyright (C) 2008-2010 by the OpenStructure authors +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation; either version 3.0 of the License, or (at your option) +// any later version. +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +//------------------------------------------------------------------------------ + +#include <ost/seq/aligned_column.hh> +#include <ost/seq/alignment_handle.hh> +#include <ost/seq/alg/conservation.hh> + +namespace ost { namespace seq { namespace alg { + +// taken from Armon et al., J. Mol. Biol. (2001) 307, 447-463 +static float CHEM_DISSIM[][24]={ + {0.00, 1.33, 1.39, 2.22, 1.84, 1.45, 2.48, 3.26, 2.83, 3.48, 2.56, 3.27, 3.06, + 0.86, 1.65, 1.63, 1.46, 2.24, 2.38, 3.34, 6.00, 6.00, 2.87, 3.15}, + {0.00, 0.06, 0.97, 0.56, 0.87, 1.92, 2.48, 1.80, 2.40, 2.15, 2.94, 2.90, 1.79, + 2.70, 2.62, 2.36, 3.17, 3.12, 4.17, 6.00, 6.00, 2.20, 2.10,-1.00}, + {0.00, 0.91, 0.51, 0.90, 1.92, 2.46, 1.78, 2.37, 2.78, 3.54, 3.58, 2.76, 3.67, + 3.60, 3.34, 4.14, 4.08, 5.13, 6.00, 6.00, 2.19, 2.08,-1.00,-1.00}, + {0.00, 0.85, 1.70, 2.48, 2.78, 1.96, 2.37, 2.78, 3.54, 3.58, 2.76, 3.67, 3.60, + 3.34, 4.14, 4.08, 5.13, 6.00, 6.00, 2.63, 2.17,-1.00,-1.00,-1.00}, + {0.00, 0.89, 1.65, 2.06, 1.31, 1.87, 1.94, 2.71, 2.74, 2.15, 3.04, 2.95, 2.67, + 3.45, 3.33, 4.38, 6.00, 6.00, 1.85, 1.59,-1.00,-1.00,-1.00,-1.00}, + {0.00, 1.12, 1.83, 1.40, 2.05, 1.32, 2.10, 3.03, 1.42, 2.25, 2.14, 1.86, 2.60, + 2.45, 3.50, 6.00, 6.00, 1.47, 1.73,-1.00,-1.00,-1.00,-1.00,-1.00}, + {0.00, 0.84, 0.99, 1.47, 0.32, 1.06, 1.30, 2.13, 2.70, 2.57, 2.30, 2.81, 2.48, + 3.42, 6.00, 6.00, 0.42, 1.23,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00}, + {0.00, 0.85, 0.90, 0.96, 1.14, 1.45, 2.97, 3.53, 3.39, 3.13, 3.59, 3.22, 4.08, + 6.00, 6.00, 0.42, 0.88,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00}, + {0.00, 0.65, 1.29, 1.84, 2.04, 2.76, 3.49, 3.37, 3.08, 3.70, 3.42, 4.39, 6.00, + 6.00, 0.92, 0.33,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00}, + {0.00, 1.72, 2.05, 2.34, 3.40, 4.10, 3.98, 3.69, 4.27, 3.95, 4.88, 6.00, 6.00, + 1.18, 0.33,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00}, + {0.00, 0.79, 0.82, 2.11, 2.59, 2.45, 2.19, 2.63, 2.27, 3.16, 6.00, 6.00, 0.64, + 1.51,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00}, + {0.00, 0.40, 2.70, 2.98, 2.84, 2.63, 2.85, 2.42, 3.11, 6.00, 6.00, 1.10, 1.95, + -1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00}, + {0.00, 2.43, 2.62, 2.49, 2.29, 2.47, 2.02, 2.72, 6.00, 6.00, 1.29, 2.19,-1.00, + -1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00}, + {0.00, 0.91, 0.85, 0.62, 1.43, 1.52, 2.51, 6.00, 6.00, 2.55, 3.08,-1.00,-1.00, + -1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00}, + {0.00, 0.14, 0.41, 0.63, 0.94, 1.73, 6.00, 6.00, 3.11, 3.80,-1.00,-1.00,-1.00, + -1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00}, + {0.00, 0.29, 0.61, 0.86, 1.72, 6.00, 6.00, 2.98, 3.68,-1.00,-1.00,-1.00,-1.00, + -1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00}, + {0.00, 0.82, 0.93, 1.89, 6.00, 6.00, 2.71, 3.39,-1.00,-1.00,-1.00,-1.00,-1.00, + -1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00}, + {0.00, 0.48, 0.11, 6.00, 6.00, 3.20, 3.99,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00, + -1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00}, + {0.00, 1.06, 6.00, 6.00, 2.85, 3.67,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00, + -1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00}, + {0.00, 6.00, 6.00, 3.75, 4.64,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00, + -1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00}, + {0.50, 6.00, 6.00, 6.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00, + -1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00}, + {0.00, 6.00, 6.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00, + -1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00}, + {0.00, 1.05,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00, + -1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00}, + {0.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00, + -1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00} +}; + +float PhysicoChemicalDissim(char c1, char c2) +{ + static int indices[]={2, 23, 0, 9, 7, 17, 3, 10, 15, -1, + 11, 14, 16, 8, -1, 1, 6, 12, 4, 5, + -1, 13, 19, 21, 18, 22}; + int idx_a=(c1=='-' || c1<'A' || c1>'Z') ? 20 : indices[c1-'A']; + int idx_b=(c2=='-' || c2<'A' || c2>'Z') ? 20 : indices[c2-'A']; + assert(idx_a>=0); + assert(idx_b>=0); + if (idx_a<0) { + idx_a=20; + } + if (idx_b<0) { + idx_b=20; + } + float s=0.0; + if (idx_a>idx_b) + s=CHEM_DISSIM[idx_b][idx_a-idx_b]; + else + s=CHEM_DISSIM[idx_a][idx_b-idx_a]; + assert(s>=0.0); + return s; +} + +std::vector<Real> Conservation(const AlignmentHandle& aln, bool assign, + const String& prop) +{ + std::vector<Real> cons(aln.GetLength(), 0.0); + int comb=aln.GetCount()*(aln.GetCount()-1)/2; + for (int col=0; col<aln.GetLength(); ++col) { + float score=0.0; + AlignedColumn c=aln[col]; + for (int i=0; i<aln.GetCount(); ++i) { + for (int j=i+1; j<aln.GetCount(); ++j) { + score+=PhysicoChemicalDissim(c[i], c[j]); + } + } + score=1.0-score/(6.0*comb); + cons[col]=score; + if (assign) { + for (int i=0; i<aln.GetCount(); ++i) { + if (c[i]!='-') { + mol::ResidueView r=c.GetResidue(i); + if (r.IsValid()) { + r.SetFloatProp(prop, score); + } + } + } + } + } + return cons; +} + +}}} + diff --git a/modules/seq/alg/src/conservation.hh b/modules/seq/alg/src/conservation.hh new file mode 100644 index 0000000000000000000000000000000000000000..b1375c4a26926881421ac0f646384e840771663f --- /dev/null +++ b/modules/seq/alg/src/conservation.hh @@ -0,0 +1,43 @@ +//------------------------------------------------------------------------------ +// This file is part of the OpenStructure project <www.openstructure.org> +// +// Copyright (C) 2008-2010 by the OpenStructure authors +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation; either version 3.0 of the License, or (at your option) +// any later version. +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +//------------------------------------------------------------------------------ + +#include <ost/seq/alignment_handle.hh> +#include <ost/seq/alg/module_config.hh> + +/* + Authors: Marco Biasini + */ +namespace ost { namespace seq { namespace alg { + +/// \brief Calculates conservation scores for each column in the alignment. +/// +/// The conservation score is a value between 0 and 1. The bigger the number +/// the more conserved the aligned residues are. +/// +/// \p assign If true, the conservation scores are assigned to attached +/// residues. The name of the property can be changed with the prop_name +/// parameter. Useful when coloring entities based on sequence conservation. +/// \p prop_name The property name for assigning the conservation to +/// attached residues. Defaults to 'cons'. +/// +std::vector<Real> DLLEXPORT_OST_SEQ_ALG Conservation(const AlignmentHandle& aln, + bool assign=true, + const String& prop_name="cons"); +}}} + diff --git a/modules/seq/base/doc/seq.rst b/modules/seq/base/doc/seq.rst new file mode 100644 index 0000000000000000000000000000000000000000..7deafe22e797a6d0c4f1ab22cc041f56e5889cbc --- /dev/null +++ b/modules/seq/base/doc/seq.rst @@ -0,0 +1,350 @@ +:mod:`~ost.seq` -- Sequences and Alignments +================================================================================ + +.. module:: ost.seq + :synopsis: Contains classes and functions to deal with sequences and + alignments + +The :mod:`seq` module helps you working with sequence data of various kinds. It +has classes for :class:`single sequences <SequenceHandle>`, :class:`lists of +sequences <SequenceList>` and :class:`alignments <AlignmentHandle>` of two or +more sequences. + + +.. _attaching-views: + +Attaching Structures to Sequences +-------------------------------------------------------------------------------- + + +Being a structural biology framework, it is not surprising that the sequence +classes have been designed to work together with structural data. Each sequence +can have an attached :class:`~mol.EntityView` allowing for fast mapping between +residues in the entity view and position in the sequence. + +.. _sequence-offset: + +Sequence Offset +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +When using sequences and structures together, often the start of the structure +and the beginning of the sequence do not fall together. In the following case, +the alignment of sequences B and C only covers a subpart of structure A:: + + A acefghiklmnpqrstuvwy + B ghiklm + C 123-45 + +We would now like to know which residue in protein A is aligned to which residue +in sequence C. This is achieved by setting the sequence offset of sequence C to +4. In essence, the sequence offset influences all the mapping operations from +position in the sequence to residue index and vice versa. By default, the +sequence offset is 0. + +Loading and Saving Sequences and Alignments +-------------------------------------------------------------------------------- + +The :mod:`io` module supports input and output of common sequence formats. +Single sequences can be loaded from disk with :func:`io.LoadSequence`, +alignments are loaded with :func:`io.LoadAlignment` and lists of sequences are loaded with :func:`io.LoadSequenceList`. In addition to the file based input +methods, sequences can also be loaded from a string: + +.. code-block:: python + + seq_string='''>sequence + abcdefghiklmnop''' + s=io.LoadSequenceFromString(seq_string, 'fasta') + print s.name, s # will print "sequence abcdefghiklmnop" + +Note that, in that case specifying the format is mandatory. + +The SequenceHandle +-------------------------------------------------------------------------------- + +.. function:: CreateSequence(name, sequence) + + Create a new :class:`SequenceHandle` with the given name and sequence. + + :param name: name of the sequence + :type name: str + :param sequence: String of characters representing the sequence. Only + alphanumerical characters and '-' are allowed. + :type sequence: str + :raises InvalidSequence: When the sequence string contains forbidden + characters, that is anything that is not alphanumeric or a hyphen. + +.. class:: SequenceHandle + + Represents a sequence. New instances are created with :func:`CreateSequence`. + + .. method:: GetPos(residue_index) + + Get position of residue with index in sequence. This is best illustrated in + the following example: + + .. code-block:: python + + s=seq.CreateSequence("A", "abc---def") + print s.GetPos(1) # prints 1 + print s.GetPos(3) # prints 6 + + The reverse mapping, that is from position in the sequence to residue index + can be achieved with :meth:`GetResidueIndex`. + + .. method:: GetResidueIndex(pos) + + Get residue index of character at given position. This method is the + inverse of :meth:`GetPos`. If the sequence contains a gap at that position, + an :exc:`Error` is raised. + + .. code-block:: python + + s=seq.CreateSequence("A", "abc--def") + print s.GetResidueIndex(1) # prints 1 + print s.GetResidueIndex(6) # prints 4 + # the following line raises an exception of type + # Error with the message "requested position contains + # a gap" + print s.GetResidueIndex(3) + + .. method:: GetLastNonGap() + + Get position of last non-gap character in sequence. In case of an empty + sequence, or, a sequence only consisting of hyphens, -1 is returned + + .. method:: GetFirstNonGap() + + Get position of first non-gap character in sequence. In case of an empty + sequence, or, a sequence only consisting of hyphens, -1 is returned. + + .. method:: AttachView(view) + AttachView(view, [chain_name]) + + Attach an :class:`~mol.EntityView` to sequence. The first signature requires + that the view contains one chain. If not, an :exc:`IntegrityError` is + raised. The second signature will select the chain with the given name. If + no such chain exists, an :exc:`IntegrityError` is raised. + + .. method:: HasAttachedView() + + Returns True when the sequence has a view attached, False if not. + + .. method:: GetAttachedView() + + Returns the attached :class:`~mol.EntityView`, or an invalid + :class:`~mol.EntityView` if no view has been attached. Also available as + the property :attr:`attached_view`. + + .. method:: GetName() + + Returns the name of the sequence. Also available as the property + :attr:`name` + + .. method:: SetSequenceOffset() + + Set the :ref:`sequence offset <sequence-offset>`. By default, the offset is + 0. Also available as the property :attr:`sequence_offset`. + + .. method:: GetSequenceOffset() + + Returns the :ref:`sequence offset <sequence-offset>`. Also available as + :attr:`sequence_offset`. + + + .. method:: GetGaplessString() + + Returns a string version of this sequence with all hyphens removed. Also + available as the property :attr:`gapless_string`. + + + .. method:: SetName() + + Set name of the sequence. Also available as the property :attr:`name`. + + .. attribute:: gapless_string + + Shorthand for :meth:`GetGaplessString()` + + .. attribute:: name + + Shorthand for :meth:`GetName`/:meth:`SetName` + + .. attribute:: attached_view + + Shorthand for :meth:`GetAttachedView`. + + .. attribute:: sequence_offset + + Shorthand for :meth:`GetSequenceOffset`/:meth:`SetSequenceOffset` + + .. method:: __len__() + + Returns the length of the sequence (including insertions and deletions) + + .. method:: __str__() + + Returns the sequence as a string. + + +The SequenceList +-------------------------------------------------------------------------------- + +.. class:: SequenceList + + Represents a list of sequences. The class provides a row-based interface. New + instances are created with :func:`CreateSequenceList`. + + +The AlignmentHandle +-------------------------------------------------------------------------------- + +The :class:`AlignmentHandle` represents a list of aligned sequences. In +constrast to :class:`SequenceList`, an alignment requires all sequences to be of +the same length. New instances of alignments are created with +:func:`CreateAlignment` and :func:`AlignmentFromSequenceList`. + +Typically sequence alignments are used column-based, i.e by looking at an +aligned columns in the sequence alignment. To get a row-based (sequence) view +on the sequence list, use :meth:`GetSequenceList()`. + +All functions that operate on an alignment will again produce a valid alignment. +This mean that it is not possible to change the length of one sequence, without +adjusting the other sequences, too. + +The following example shows how to iterate over the columns and sequences of +an alignment: + +.. code-block:: python + + aln=io.LoadAlignment('aln.fasta') + # iterate over the columns + for col in aln: + print col + + # iterate over the sequences + for s in aln.sequences: + print s + +.. function:: CreateAlignment() + + Creates and returns a new :class:`AlignmentHandle` with no sequences. + +.. function:: AlignmentFromSequenceList(sequences) + + Create a new alignment from the given list of sequences + + :param sequences: the list of sequences + :type sequences: :class:`ConstSequenceList` + + :raises: :exc:`InvalidAlignment` if the sequences do not have the same length. + +.. class:: AlignmentHandle + + .. note:: + + Several of these methods just forward calls to the sequence. For more + detailed information, have a look at the :class:`SequenceHandle` + documentation. + + .. method:: GetSequence(index) + + Returns the sequence at the given index, raising an IndexError when trying + to access an inexistent sequence. + + .. method:: GetSequenceList() + + Returns a list of all sequence of the alignment. + + .. method:: GetLength() + + Returns the length of the alignment. + + .. method:: GetCount() + + Returns the number of sequences in the alignment. + + + .. method:: ToString(width=80) + + Returns a formatted string version of the alignment. The sequences are + split into smaller parts to fit into the number columns specified. + + .. code-block:: python + + aln=seq.CreateAlignment() + aln.AddSequence(seq.CreateSequence("A", "abcdefghik")) + aln.AddSequence(seq.CreateSequence("B", "1234567890")) + # The following command will print the output given below + print aln.ToString(7) + # A abcde + # B 12345 + # + # A fghik + # B 67890 + + .. method:: FindSequence(name) + + Find sequence with given name. If the alignment contains several sequences + with the same name, the first sequence is returned. + + .. method:: SetSequenceName(seq_index, name) + + Set the name of the sequence at index `seq_index` to name + + .. method:: SetSequenceOffset(seq_index, offset) + + Set the sequence offset of sequence at index `seq_index` + + .. method:: Copy() + + Create a deep copy of the alignment + + .. method:: GetPos(seq_index, res_index) + + Get position of residue with index equal to `res_index` in sequence at index + `seq_index`. + + .. method:: GetResidueIndex(seq_index, pos) + + Get residue index of residue at position `pos` in sequence at index + `seq_index`. + + .. method:: AttachView(seq_index, view) + AttachView(seq_index, view, chain_name) + + Attach the given view to the sequence at index `seq_index`. + + .. method:: Cut(start, end) + + Removes the columns in the half-closed interval `start`, `end` from the + alignment. + + .. code-block:: python + + aln=seq.CreateAlignment() + aln.AddSequence(seq.CreateSequence("A", "abcd---hik")) + aln.AddSequence(seq.CreateSequence("B", "1234567890")) + aln.Cut(4, 7) + + print aln.ToString(80) + # will print + # A abcdhik + # B 1234890 + + .. method:: Replace(new_region, start, end) + + Replace the columns in the half-closed interval `start`, `end` with the + columns in `new_region`. + + :param new_region: The region to be inserted + :type new_region: :class:`AlignedRegion` or :class:`AlignmentHandle` + + + .. method:: ShiftRegion(start, end, amount, master=-1) + + Shift columns in the half-closed interval `start`, `end`. If amount is a + positive number, the columns are shifted to the right, if negative, the + columns are shifted to the left. + + If master is set to -1, all sequences in the region are affected, otherwise + only the sequence at index equal to master is shifted. diff --git a/modules/seq/base/pymod/__init__.py b/modules/seq/base/pymod/__init__.py index 6b92feb561d921cbf76caba2939286e5b5ca2c9f..0bc8f1b300e952bbf5ce5ae9bd52cbf9735c3420 100644 --- a/modules/seq/base/pymod/__init__.py +++ b/modules/seq/base/pymod/__init__.py @@ -16,100 +16,4 @@ # along with this library; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #------------------------------------------------------------------------------ -from _seq import * -from ost import mol - -def ViewsFromAlignment(multi_seq_ali, ent_a, ent_b, include_atoms=True): - seq_a=multi_seq_ali.GetSequence(0) - seq_b=multi_seq_ali.GetSequence(1) - - # set offset according to ent_a and ent_b - - - return ViewsFromSequences(seq_a, seq_b, ent_a, ent_b, include_atoms) - -def ViewsFromSequences(seq_a, seq_b, ent_a=None, ent_b=None, - include_atoms=True): - ent_a=ent_a or seq_a.attached_view - ent_b=ent_b or seq_b.attached_view - if ent_a.chain_count>1: - raise RuntimeError("first entity contains more than one chain") - if ent_b.chain_count>1: - raise RuntimeError("second entity contains more than one chain") - is_ha=isinstance(ent_a, mol.EntityHandle) - is_hb=isinstance(ent_b, mol.EntityHandle) - - ev_a= is_ha and ent_a.CreateEmptyView() or ent_a.handle.CreateEmptyView() - ev_b= is_hb and ent_b.CreateEmptyView() or ent_b.handle.CreateEmptyView() - - flags=include_atoms and mol.ViewAddFlag.INCLUDE_ATOMS or 0 - # get all residues - res_a=ent_a.residues - res_b=ent_b.residues - - # map sequence onto - s1 = seq_a.gapless_string - s2 = seq_b.gapless_string - - # get sequence of ent1 - seq_ent_a = "" - seq_ent_b= "" - - sub_a = ent_a.Select("peptide = 1") - sub_b = ent_b.Select("peptide = 1") - for res1 in sub_a.residues: - seq_ent_a = "%s%s" % (seq_ent_a, res1.one_letter_code) - - seq_ent_b = "" - for res2 in sub_b.residues: - seq_ent_b = "%s%s" % (seq_ent_b, res2.one_letter_code) - - #~ print seq_ent_a - #~ print s1 - - #~ print seq_ent_a - #~ print s1 - off_a = seq_ent_a.index(s1) - off_b = seq_ent_b.index(s2) - - #off_a=seq_a.GetSequenceOffset() - #off_b=seq_b.GetSequenceOffset() - - - index_a, index_b=(0, 0) - done=False - - align_index = 0 - - # iterate over residues - while index_a<seq_a.GetLength() and index_b<seq_b.GetLength(): - # print 'index',index_a, seq_a.GetLength(), index_b, seq_b.GetLength() - while seq_a.GetOneLetterCode(index_a)=='-': - index_a+=1 - if seq_a.GetLength()<index_a: - done=True - break - while seq_b.GetOneLetterCode(index_b)=='-': - index_b+=1 - if seq_b.GetLength()<index_b: - done=True - break - if done or len(res_a)<=off_a+index_b or len(res_b)<=off_b+index_a: - break - ra=res_a[off_a+index_b] - rb=res_b[off_b+index_a] - #ra = res_a[index_b] - #rb = res_a[index_a] - #~ print "set align_index %d for %s %s" % (align_index, ra, rb) - #ra.SetIntProp("align_index",align_index) - #rb.SetIntProp("align_index",align_index) - align_index += 1 - ev_a.AddResidue(is_ha and ra or ra.handle, flags) - ev_b.AddResidue(is_hb and rb or rb.handle, flags) - index_a+=1 - index_b+=1 - eda=ev_a.handle.RequestXCSEditor() - eda.RenameChain(ent_a.chains[0].handle,ent_a.chains[0].name) - edb=ev_b.handle.RequestXCSEditor() - edb.RenameChain(ent_b.chains[0].handle, ent_b.chains[0].name) - return ev_a, ev_b +from _seq import * \ No newline at end of file diff --git a/modules/seq/base/pymod/const_seq_list_export_def.hh b/modules/seq/base/pymod/const_seq_list_export_def.hh index 4c8a2706853882c58b4bce556cf89bbb523e061b..baba8115839726d0ecc8e7f3acc063d35efc1f71 100644 --- a/modules/seq/base/pymod/const_seq_list_export_def.hh +++ b/modules/seq/base/pymod/const_seq_list_export_def.hh @@ -23,11 +23,11 @@ .def("AddSequence", &C::AddSequence) \ .def("GetMaxLength", &C::GetMaxLength) \ .def("GetMinLength", &C::GetMinLength) \ + .def("IsValid", &C::IsValid) \ .def("Take", &C::Take) \ - .def("Slice", &C::Slice) \ + .def("Slice", &C::Slice) \ .def("SequencesHaveEqualLength", \ &C::SequencesHaveEqualLength) \ .def("__getitem__", &C::operator[]) \ - .def("__iter__", iterator<C>()) \ .def("__len__", &C::GetCount) diff --git a/modules/seq/base/pymod/export_sequence.cc b/modules/seq/base/pymod/export_sequence.cc index 581c5494c2ad3386d672dda08223e8d0e45706f4..ee33b6125cd8fe63b8b5f390b72e0f6c4318ca45 100644 --- a/modules/seq/base/pymod/export_sequence.cc +++ b/modules/seq/base/pymod/export_sequence.cc @@ -20,8 +20,9 @@ #include <boost/python/slice.hpp> #include <boost/python/register_ptr_to_python.hpp> #include <boost/python/suite/indexing/vector_indexing_suite.hpp> -using namespace boost::python; + +#include <ost/export_helper/pair_to_tuple_conv.hh> #include <ost/generic_property.hh> #include <ost/export_helper/generic_property_def.hh> #include <ost/info/info.hh> @@ -31,11 +32,12 @@ using namespace boost::python; #include <ost/seq/sequence_op.hh> #include <ost/seq/sequence_list.hh> #include <ost/seq/aligned_region.hh> +#include <ost/seq/views_from_sequences.hh> #include "const_seq_list_export_def.hh" using namespace ost; using namespace ost::seq; - +using namespace boost::python; namespace { void (SequenceHandle::*attach_one)(const mol::EntityView&)=&SequenceHandle::AttachView; @@ -102,8 +104,9 @@ struct RevRegionRangeIter { if (b_==e_) { boost::python::objects::stop_iteration_error(); } - AlignedColumn col=*e_; --e_; + AlignedColumn col=*e_; + return col; } private: @@ -131,6 +134,55 @@ private: AlignedColumnIterator e_; }; +struct ConstSeqListIter { + ConstSeqListIter(ConstSequenceList& list): + l_(list), b_(l_.begin()), e_(l_.end()) + { } + + ConstSequenceHandle next() + { + if (b_==e_) { + boost::python::objects::stop_iteration_error(); + } + ConstSequenceHandle s=*b_; + ++b_; + return s; + } +private: + ConstSequenceList l_; + ConstSequenceList::iterator b_; + ConstSequenceList::iterator e_; +}; + +struct SeqListIter { + SeqListIter(SequenceList& list): + l_(list), b_(l_.begin()), e_(l_.end()) + { } + + SequenceHandle next() + { + if (b_==e_) { + boost::python::objects::stop_iteration_error(); + } + SequenceHandle s=*b_; + ++b_; + return s; + } +private: + SequenceList l_; + SequenceList::iterator b_; + SequenceList::iterator e_; +}; + +ConstSeqListIter iter_cs(ConstSequenceList& sl) +{ + return ConstSeqListIter(sl); +} + +SeqListIter iter_sl(SequenceList& sl) +{ + return SeqListIter(sl); +} RegionRangeIter iter_range1(AlignmentHandle& aln) { @@ -142,7 +194,7 @@ RegionRangeIter iter_range2(AlignedRegion& aln_region) return RegionRangeIter(aln_region.begin(), aln_region.end()); } -RevRegionRangeIter iter_range3(AlignedRegion& aln_region) +RevRegionRangeIter iter_range_rev(AlignedRegion& aln_region) { return RevRegionRangeIter(aln_region.begin(), aln_region.end()); } @@ -159,6 +211,7 @@ void const_seq_handle_def(O& bp_class) .def("__getitem__", &C::GetOneLetterCode) .def("GetSequenceOffset", &C::GetSequenceOffset) .def("Copy", &C::Copy) + .def("IsValid", &C::IsValid) .def("GetFirstNonGap", &C::GetFirstNonGap) .def("GetLastNonGap", &C::GetLastNonGap) .add_property("first_non_gap", &C::GetFirstNonGap) @@ -226,6 +279,12 @@ void export_sequence() class_<RevRegionRangeIter>("RevRegionRangeIter", no_init) .def("next", &RevRegionRangeIter::next) ; + class_<ConstSeqListIter>("ConstSeqListIter", no_init) + .def("next", &ConstSeqListIter::next) + ; + class_<SeqListIter>("SeqListIter", no_init) + .def("next", &SeqListIter::next) + ; class_<AlignmentHandle>("AlignmentHandle", init<>()) .def("GetCount", &AlignmentHandle::GetCount) .add_property("sequence_count", &AlignmentHandle::GetCount) @@ -250,11 +309,13 @@ void export_sequence() .add_property("sequences", &AlignmentHandle::GetSequences) .def("SetSequenceName", &AlignmentHandle::SetSequenceName) .def("SetSequenceOffset", &AlignmentHandle::SetSequenceOffset) + .def("GetSequenceOffset", &AlignmentHandle::GetSequenceOffset) ; class_<AlignedColumn>("AlignedColumn", no_init) .def("GetIndex", &AlignedColumn::GetIndex) .def("__getitem__", &AlignedColumn::operator[]) .def("GetRowCount", &AlignedColumn::GetRowCount) + .def("GetResidue", &AlignedColumn::GetResidue) .def(self_ns::str(self)) ; class_<AlignedRegion>("AlignedRegion", no_init) @@ -273,27 +334,34 @@ void export_sequence() .def("__getitem__", &AlignedRegion::operator[]) .def("__len__", &AlignedRegion::GetLength) .def("__iter__", iter_range2) - //~ .def("__iter__", iter_range3) + //~ .def("__reversed__", iter_range_rev) .add_property("start", &AlignedRegion::GetStart) .add_property("end", &AlignedRegion::GetEnd) ; class_<ConstSequenceList>("ConstSequenceList", init<>()) CONST_SEQ_LIST_DEF(ConstSequenceList) .def("__getitem__", &do_slice_a) + .def("__iter__", &iter_cs) ; class_<SequenceList>("SequenceList", init<>()) CONST_SEQ_LIST_DEF(SequenceList) .def("__getitem__", &do_slice_b) + .def("__iter__", &iter_sl) ; class_<AlignmentList>("AlignmentList", init<>()) .def(vector_indexing_suite<AlignmentList>()) .def("__getitem__", &do_slice_b) ; implicitly_convertible<SequenceList, ConstSequenceList>(); + to_python_converter<std::pair<mol::EntityView, mol::EntityView>, + PairToTupleConverter<mol::EntityView, mol::EntityView> >(); def("CreateSequenceList", &CreateSequenceList); def("SequenceFromChain", seq_from_chain_a); def("SequenceFromChain", seq_from_chain_b); def("SequenceToInfo", &SequenceToInfo); + def("ViewsFromSequences", &ViewsFromSequences, (arg("seq1"), arg("seq2"))); + def("ViewsFromAlignment", &ViewsFromAlignment, + (arg("aln"), arg("index1")=0, arg("index2")=1)); def("SequenceListToInfo", &SequenceListToInfo); def("SequenceFromInfo", &SequenceFromInfo); def("CreateAlignment", &CreateAlignment); diff --git a/modules/seq/base/src/CMakeLists.txt b/modules/seq/base/src/CMakeLists.txt index 3cd12d19a6af292471fde3dbb6d85c32e5eaaef5..9a7015bdae3e8162ab76c711893a70e874fea101 100644 --- a/modules/seq/base/src/CMakeLists.txt +++ b/modules/seq/base/src/CMakeLists.txt @@ -15,6 +15,7 @@ aligned_region.hh aligned_column.hh aligned_column_iterator.hh invalid_sequence.hh +views_from_sequences.hh ) set(OST_SEQ_SOURCES @@ -26,6 +27,7 @@ aligned_column.cc sequence_list.cc alignment_handle.cc sequence_op.cc +views_from_sequences.cc ) module(NAME seq SOURCES ${OST_SEQ_SOURCES} HEADERS ${OST_SEQ_IMPL_HEADERS} IN_DIR impl diff --git a/modules/seq/base/src/aligned_column.cc b/modules/seq/base/src/aligned_column.cc index 8f5f1081c09633766b8ede9797807af8a7e29bd2..e07e828b5d91b685aef767d574f72223b37d12d9 100644 --- a/modules/seq/base/src/aligned_column.cc +++ b/modules/seq/base/src/aligned_column.cc @@ -38,16 +38,19 @@ int AlignedColumn::GetIndex() const char AlignedColumn::operator[](int row) const { + this->CheckRowValidity(row); return aln_.GetOneLetterCode(row, index_); } int AlignedColumn::GetResidueIndex(int row) const { + this->CheckRowValidity(row); return aln_.GetResidueIndex(row, index_); } mol::ResidueView AlignedColumn::GetResidue(int row) const { + this->CheckRowValidity(row); return aln_.GetResidue(row, index_); } @@ -64,4 +67,12 @@ int AlignedColumn::GetRowCount() const return aln_.GetCount(); } +void AlignedColumn::CheckRowValidity(int row) const +{ + if(row<0 || row>=this->GetRowCount()){ + throw std::out_of_range("Row out of bounds"); + } +} + + }} diff --git a/modules/seq/base/src/aligned_column.hh b/modules/seq/base/src/aligned_column.hh index 2ea6e5ccabc87da2a559e19cd678b52dd7d49688..75bdf6fd31cd174458166887fc7d03e53edc5621 100644 --- a/modules/seq/base/src/aligned_column.hh +++ b/modules/seq/base/src/aligned_column.hh @@ -55,6 +55,8 @@ public: /// \sa AlignmentHandle::GetResidue() mol::ResidueView GetResidue(int row) const; private: + void CheckRowValidity(int row) const; + AlignmentHandle aln_; int index_; }; diff --git a/modules/seq/base/src/aligned_region.cc b/modules/seq/base/src/aligned_region.cc index decb966ef0533f5c9d0a1383d4f8ccb2f1ce36e4..fc4a3c6d69b41513e43ffdde09e1809b27a391a0 100644 --- a/modules/seq/base/src/aligned_region.cc +++ b/modules/seq/base/src/aligned_region.cc @@ -94,7 +94,11 @@ AlignedColumnIterator AlignedRegion::end() AlignedColumn AlignedRegion::operator[](int index) const { - return AlignedColumn(aln_, start_+index); + int col_index = start_+index; + if(col_index<start_ || col_index>=end_){ + throw std::out_of_range("Index out of region"); + } + return AlignedColumn(aln_, col_index); } bool AlignedRegion::operator==(const AlignedRegion& rhs) const @@ -115,6 +119,9 @@ int AlignedRegion::GetMaster() const void AlignedRegion::SetMaster(int master) { + if(master < -1 || master >= aln_.GetCount()){ + throw IntegrityError("Master out of bounds"); + } master_=master; } diff --git a/modules/seq/base/src/alignment_handle.cc b/modules/seq/base/src/alignment_handle.cc index 48bb07af5fb0dad628d188aa32ccbeb722e99fc4..d4611b5623a69ec8bcfd653f7dd66fd3e2513981 100644 --- a/modules/seq/base/src/alignment_handle.cc +++ b/modules/seq/base/src/alignment_handle.cc @@ -62,9 +62,9 @@ int AlignmentHandle::GetResidueIndex(int seq_index, int pos) const void AlignmentHandle::AddSequence(const ConstSequenceHandle& sequence) { this->CheckValidity(); - if (impl_->GetCount()>0 && - impl_->GetSequence(0)->GetLength()!=sequence.GetLength()) { - throw InvalidAlignment(); + if (!sequence.IsValid() || (impl_->GetCount()>0 && + impl_->GetSequence(0)->GetLength()!=sequence.GetLength())) { + throw InvalidSequence(); } return impl_->AddSequence(sequence.Impl()); } @@ -124,7 +124,7 @@ int AlignmentHandle::GetCount() const AlignmentHandle AlignmentFromSequenceList(const SequenceList& seq_list) { - if (seq_list.SequencesHaveEqualLength()) { + if (seq_list.IsValid() && seq_list.SequencesHaveEqualLength()) { return AlignmentHandle(seq_list.Impl()); } throw InvalidAlignment(); @@ -143,7 +143,7 @@ void AlignmentHandle::AttachView(int seq_index, const mol::EntityView& view) impl_->GetSequence(seq_index)->AttachView(view); } -void AlignmentHandle::AttachView(int seq_index, const mol::EntityView& view, +void AlignmentHandle::AttachView(int seq_index, const mol::EntityView& view, const String& chain_name) { this->CheckValidity(); @@ -160,7 +160,7 @@ ConstSequenceHandle AlignmentHandle::FindSequence(const String& name) const void AlignmentHandle::Cut(int start, int end) { this->CheckValidity(); - for (impl::SequenceListImpl::Iterator i=impl_->Begin(), + for (impl::SequenceListImpl::Iterator i=impl_->Begin(), e=impl_->End(); i!=e; ++i) { (*i)->Cut(start, end-start); } @@ -170,28 +170,33 @@ void AlignmentHandle::Replace(const AlignedRegion& aln_r, int start, int end){ this->CheckValidity(); //check that alignment handle and aligned region contain same number of sequences if (impl_->GetCount() != aln_r.GetAlignmentHandle().GetCount()) { - throw IntegrityError("alignment handle and aligned region are required "\ - "to share the same number of sequences"); + throw IntegrityError("alignment handle and aligned region are required " + "to have the same number of sequences"); } - int aln_rStart=aln_r.GetStart(); - int aln_rEnd=aln_r.GetEnd(); + int aln_r_start=aln_r.GetStart(); + int aln_r_length=aln_r.GetLength(); AlignmentHandle aln=aln_r.GetAlignmentHandle(); //iterate over sequences and replace part of sequences with the substrings //from aligned region for (int i=0;i<impl_->GetCount() ;++i) { - this->GetSequence(i).Impl()->Replace(aln.GetSequence(i).GetString().substr(aln_rStart,aln_rEnd), start, end); + String s=aln.GetSequence(i).GetString().substr(aln_r_start, aln_r_length); + this->GetSequence(i).Impl()->Replace(s, start, end); } } -void AlignmentHandle::ShiftRegion(int start, int end, int amount, +void AlignmentHandle::ShiftRegion(int start, int end, int amount, int master) { this->CheckValidity(); int cnt=0; - for (impl::SequenceListImpl::Iterator i=impl_->Begin(), - e=impl_->End(); i!=e; ++i, ++cnt) { - if (master==-1 || cnt==master) { - (*i)->ShiftRegion(start, end, amount); + if(master!=-1){ + impl::SequenceImplPtr handle = this->GetSequence(master).Impl(); + handle->ShiftRegion(start, end, amount); + } + else{ + for (impl::SequenceListImpl::Iterator i=impl_->Begin(), + e=impl_->End(); i!=e; ++i, ++cnt) { + (*i)->ShiftRegion(start, end, amount); } } } @@ -199,6 +204,9 @@ void AlignmentHandle::ShiftRegion(int start, int end, int amount, AlignedRegion AlignmentHandle::MakeRegion(int start, int n, int master) const { this->CheckValidity(); + if((start<0 )||( n < 0 )|| ((start + n) > this->GetLength())){ + throw std::out_of_range("invalid region"); + } return AlignedRegion(*this, start, start+n, master); } @@ -216,7 +224,7 @@ char AlignmentHandle::GetOneLetterCode(int seq_index, int pos) const AlignedColumnIterator AlignmentHandle::begin() const { - // no need to check for validity here + // no need to check for validity here return AlignedColumnIterator(*this, 0, this->GetLength()); } @@ -244,4 +252,9 @@ void AlignmentHandle::SetSequenceOffset(int seq_index, int offset) impl_->GetSequence(seq_index)->SetSequenceOffset(offset); } +int AlignmentHandle::GetSequenceOffset(int seq_index) +{ + this->CheckValidity(); + return impl_->GetSequence(seq_index)->GetSequenceOffset(); +} }} diff --git a/modules/seq/base/src/alignment_handle.hh b/modules/seq/base/src/alignment_handle.hh index 7e6ba856767795ae3ef7882f898b7cfffb0559e2..998618b520ed6e90fa88b81f45ddadf4f4e5dcaa 100644 --- a/modules/seq/base/src/alignment_handle.hh +++ b/modules/seq/base/src/alignment_handle.hh @@ -35,27 +35,27 @@ class AlignedRegion; class AlignedColumn; class AlignedColumnIterator; -/// \brief representation of a multiple sequence alignemnt consisting of two or +/// \brief representation of a multiple sequence alignemnt consisting of two or /// more sequences /// -/// A sequence alignment consists of two or more sequences. The number of -/// sequences in the alignment can be obtained by #GetCount(). +/// A sequence alignment consists of two or more sequences. The number of +/// sequences in the alignment can be obtained by #GetCount(). /// All sequences are of length #GetLength(). -/// -/// Typically sequence alignments are used column-based, i.e by looking at an -/// aligned columns in the sequence alignment. To get a row-based (sequence) -/// view on the sequence list, use AlignmentHandle::GetSequenceList(). For an +/// +/// Typically sequence alignments are used column-based, i.e by looking at an +/// aligned columns in the sequence alignment. To get a row-based (sequence) +/// view on the sequence list, use AlignmentHandle::GetSequenceList(). For an /// overview of how to use the sequence module, see \ref module_seq "here" -/// -/// All operators that operate on an alignment will again produce a valid -/// alignment. This mean that it is not possible to change the length of one +/// +/// All operators that operate on an alignment will again produce a valid +/// alignment. This mean that it is not possible to change the length of one /// sequence, without adjusting the other sequences, too. class DLLEXPORT_OST_SEQ AlignmentHandle { public: typedef AlignedColumnIterator iterator; AlignmentHandle(); - + /// \brief Get position in sequence with index seq_index that corresponds to /// the given residue index. /// @@ -68,19 +68,19 @@ public: int GetResidueIndex(int seq_index, int pos) const; mol::ResidueView GetResidue(int seq_index, int pos) const; - + char GetOneLetterCode(int seq_index, int pos) const; - + /// \brief Add new sequence to multiple sequence alignment. - /// - /// If the sequence length does not match with the length of the other + /// + /// If the sequence length does not match with the length of the other /// sequences in the alignment, an InvalidSequence() exception is thrown. void AddSequence(const ConstSequenceHandle& sequence); /// \brief Get sequence with given index. /// \return sequence or invalid handle if the index is out of bounds - ConstSequenceHandle GetSequence(int seq_id) const; - + ConstSequenceHandle GetSequence(int seq_id) const; + /// \brief Convert multiple sequence alignment to string. String ToString(int width=80) const; @@ -88,87 +88,87 @@ public: int GetLength() const; /// \brief deep-copy multi sequence alignment - AlignmentHandle Copy() const; - + AlignmentHandle Copy() const; + /// \brief find sequence by name. - /// - /// If several sequences have the same name, the first matching sequence will + /// + /// If several sequences have the same name, the first matching sequence will /// be returned. ConstSequenceHandle FindSequence(const String& name) const; - + /// \brief attach view to given sequence /// \sa SequenceHandle::AttachView(const mol::EntityView&) void AttachView(int seq_index, const mol::EntityView& view); - + /// \brief attach view to given sequence - /// \sa SequenceHandle::AttachView(const mol::EntityView&, const String&) - void AttachView(int seq_index, const mol::EntityView& view, + /// \sa SequenceHandle::AttachView(const mol::EntityView&, const String&) + void AttachView(int seq_index, const mol::EntityView& view, const String& chain_name); - + /// \brief set name of sequence void SetSequenceName(int seq_index, const String& name); - - void SetSequenceOffset(int seq_index, int offset); + + void SetSequenceOffset(int seq_index, int offset); + int GetSequenceOffset(int seq_index); /// \brief Get list of sequences (read-only) ConstSequenceList GetSequences() const; - + /// \brief create an aligned region. - /// + /// /// \param start is the index of the first column /// \param n is the length of the sequence - /// \param master is the reference system for operations such as shifting. - /// If set to -1, no master sequence is defined and the operations will + /// \param master is the reference system for operations such as shifting. + /// If set to -1, no master sequence is defined and the operations will /// affect all sequences - /// - /// This method does not throw any exceptions, even if the aligned region is - /// out of bounds. + /// + /// If the aligned region is out of bounds, a std::out_of_bounds exeception will be thrown. AlignedRegion MakeRegion(int start, int n, int master=-1) const; - + /// \brief get number of sequences in alignment int GetCount() const; - + bool operator==(const AlignmentHandle& rhs) const; - bool operator!=(const AlignmentHandle& rhs) const; - + bool operator!=(const AlignmentHandle& rhs) const; + /// \brief get aligned column at index - /// - /// This method does not throw any exception. Upon accessing methods of the - /// aligned column, exceptions might be thrown when the index is out of + /// + /// This method does not throw any exception. Upon accessing methods of the + /// aligned column, exceptions might be thrown when the index is out of /// bounds. AlignedColumn operator[](int index) const; - - AlignmentHandle(const impl::SequenceListImplPtr& impl); - + + AlignmentHandle(const impl::SequenceListImplPtr& impl); + /// \brief cut out half-closed interval start, end void Cut(int start, int end); - + ///\brief Replace part of an alignment void Replace(const AlignedRegion& rhs, int start, int end); /// \brief shift half-closed interval by amount - /// + /// /// if master is -1, all sequences of the alignment will be shifted. Otherwise /// only the sequence with given index is affected. void ShiftRegion(int start, int end, int amount, int master=-1); - + /// \brief Column iterator start-point iterator begin() const; /// \brief Column iterator end-point iterator end() const; - + private: void CheckValidity() const; - impl::SequenceListImplPtr impl_; + impl::SequenceListImplPtr impl_; }; AlignmentHandle DLLEXPORT_OST_SEQ CreateAlignment(); /// \brief convert alignment from sequence list -/// -/// If the sequences in the SequenceList have different lengths, an +/// +/// If the sequences in the SequenceList have different lengths, an /// InvalidAlignment exception is thrown. -/// +/// /// \return alignment consisting of the sequences in seq_list. -AlignmentHandle DLLEXPORT_OST_SEQ +AlignmentHandle DLLEXPORT_OST_SEQ AlignmentFromSequenceList(const SequenceList& seq_list); typedef std::vector<AlignmentHandle> AlignmentList; diff --git a/modules/seq/base/src/impl/sequence_impl.cc b/modules/seq/base/src/impl/sequence_impl.cc index 69fd3f42f4d3cd3b377f2991e282ff27d86ba116..06edaf5d52067124afb76f6a3335c9844e1f3ed6 100644 --- a/modules/seq/base/src/impl/sequence_impl.cc +++ b/modules/seq/base/src/impl/sequence_impl.cc @@ -63,8 +63,13 @@ SequenceImplPtr SequenceImpl::FromString(const String& seq_name, void SequenceImpl::SetString(const String& seq) { - seq_string_=seq; - this->ShiftsFromSequence(); + if (SequenceImpl::IsSequenceStringSane(seq)) { + seq_string_=seq; + this->ShiftsFromSequence(); + } + else { + throw InvalidSequence(); + } } SequenceImpl::SequenceImpl(const String& seq_name, @@ -165,6 +170,8 @@ int SequenceImpl::GetLength() const { char SequenceImpl::GetOneLetterCode(int position) const { + if (position<0 || position>=static_cast<int>(seq_string_.length())) + throw Error("Position is not covered in sequence"); return seq_string_[position]; } @@ -207,7 +214,7 @@ void SequenceImpl::AttachView(const mol::EntityView& view) { static const char* msg="Expected 1 chain, but %d chains found"; attached_view_=view; - if (attached_view_.GetChainCount()!=1) { + if (view.IsValid() && attached_view_.GetChainCount()!=1) { throw IntegrityError(str(format(msg) % attached_view_.GetChainCount())); } } @@ -273,6 +280,9 @@ void SequenceImpl::Replace(const String& str,int start, int end) void SequenceImpl::ShiftRegion(int start, int end, int amount) { + if(start > end || start + amount < 0 || end + amount > this->GetLength()){ + throw std::out_of_range("ShiftRegion: invalid region"); + } String str1=seq_string_.substr(start, end-start); if (amount<0) { String str2=seq_string_.substr(start+amount, -amount); diff --git a/modules/seq/base/src/impl/sequence_list_impl.hh b/modules/seq/base/src/impl/sequence_list_impl.hh index 0911aa9b8b136a1caa000e62eb6b88978493f4b2..93bc070353780e6c90ddc24add126b5a10560d12 100644 --- a/modules/seq/base/src/impl/sequence_list_impl.hh +++ b/modules/seq/base/src/impl/sequence_list_impl.hh @@ -41,12 +41,21 @@ public: /// \brief get number of sequences in list int GetCount() const { return list_.size(); } - SequenceImplPtr& GetSequence(int i) - { - return list_[i]; + SequenceImplPtr& GetSequence(int i) { + unsigned int index = static_cast<unsigned int>(i); + if (index<list_.size()) { + return list_[index]; + } + throw Error("Index not covered SequenceList"); } - const SequenceImplPtr& GetSequence(int i) const { return list_[i]; } + const SequenceImplPtr& GetSequence(unsigned int i) const { + unsigned int index = static_cast<unsigned int>(i); + if (index<list_.size()) { + return list_[index]; + } + throw Error("Index not covered SequenceList"); + } int GetPos(int seq_index, int residue_index) const; diff --git a/modules/seq/base/src/sequence_handle.cc b/modules/seq/base/src/sequence_handle.cc index eeb3d1acb8f363c750c3327e7e4a648d36f88a9c..a7f5347e1f36521635b28d4ef6076b0c876ef8a0 100644 --- a/modules/seq/base/src/sequence_handle.cc +++ b/modules/seq/base/src/sequence_handle.cc @@ -51,6 +51,11 @@ bool ConstSequenceHandle::operator!=(const ConstSequenceHandle& rhs) const return impl_!=rhs.impl_; } +char ConstSequenceHandle::operator[](int index) const +{ + this->CheckValidity(); + return this->GetOneLetterCode(index); +} void ConstSequenceHandle::CheckValidity() const { diff --git a/modules/seq/base/src/sequence_handle.hh b/modules/seq/base/src/sequence_handle.hh index ad4d294e33f518cc6575ff1aed82df63db3397c3..de03a505be77b43ad87b9c5d97edf2a9a681a01b 100644 --- a/modules/seq/base/src/sequence_handle.hh +++ b/modules/seq/base/src/sequence_handle.hh @@ -116,6 +116,8 @@ public: bool operator==(const ConstSequenceHandle& rhs) const; bool operator!=(const ConstSequenceHandle& rhs) const; + char operator[](int index) const; + /// \brief whether the sequence is valid bool IsValid() const; /// \internal diff --git a/modules/seq/base/src/views_from_sequences.cc b/modules/seq/base/src/views_from_sequences.cc new file mode 100644 index 0000000000000000000000000000000000000000..7ab0ff1f6806c1d303baac5e0689f12d06d91f89 --- /dev/null +++ b/modules/seq/base/src/views_from_sequences.cc @@ -0,0 +1,87 @@ +//------------------------------------------------------------------------------ +// This file is part of the OpenStructure project <www.openstructure.org> +// +// Copyright (C) 2008-2010 by the OpenStructure authors +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation; either version 3.0 of the License, or (at your option) +// any later version. +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +//------------------------------------------------------------------------------ +#include <ost/integrity_error.hh> +#include <ost/seq/views_from_sequences.hh> + +namespace ost { namespace seq { + +namespace { + +bool skip_gaps(const ConstSequenceHandle& seq1, + const ConstSequenceHandle& seq2, int& pos, + int& index_a, int& index_b) +{ + while (seq1.GetLength()>pos) { + if (seq1[pos]=='-') { + if (seq2[pos]!='-') { + index_b+=1; + } + } else if (seq2[pos]=='-') { + index_a+=1; + } else { + return true; + } + pos+=1; + } + return false; +} + +} + +std::pair<mol::EntityView, mol::EntityView> +ViewsFromSequences(const ConstSequenceHandle& seq1, + const ConstSequenceHandle& seq2) +{ + if (seq1.GetLength()!=seq2.GetLength()) { + throw IntegrityError("Sequence lengths do not match"); + } + if (!seq1.HasAttachedView()) { + throw IntegrityError("First sequence does not have an attached view"); + } + if (!seq2.HasAttachedView()) { + throw IntegrityError("Second sequence does not have an attached view"); + } + mol::EntityView src_a=seq1.GetAttachedView(); + mol::EntityView src_b=seq2.GetAttachedView(); + + mol::EntityView dst_a=src_a.CreateEmptyView(); + mol::EntityView dst_b=src_b.CreateEmptyView(); + mol::ResidueViewList res_a=src_a.GetResidueList(); + mol::ResidueViewList res_b=src_b.GetResidueList(); + int pos=0, index_a=0, index_b=0; + while (skip_gaps(seq1, seq2, pos, index_a, index_b)) { + dst_a.AddResidue(res_a.at(seq1.GetSequenceOffset()+index_a), + mol::ViewAddFlag::INCLUDE_ATOMS); + dst_b.AddResidue(res_b.at(seq2.GetSequenceOffset()+index_b), + mol::ViewAddFlag::INCLUDE_ATOMS); + pos+=1; + index_a+=1; + index_b+=1; + } + return std::make_pair(dst_a, dst_b); +} + + +std::pair<mol::EntityView, mol::EntityView> +ViewsFromAlignment(const AlignmentHandle& aln, int index1, int index2) +{ + return ViewsFromSequences(aln.GetSequence(index1), aln.GetSequence(index2)); +} + +}} diff --git a/modules/seq/base/src/views_from_sequences.hh b/modules/seq/base/src/views_from_sequences.hh new file mode 100644 index 0000000000000000000000000000000000000000..1a46965b1a7078038bc868090a1b9d590d3c5376 --- /dev/null +++ b/modules/seq/base/src/views_from_sequences.hh @@ -0,0 +1,36 @@ +//------------------------------------------------------------------------------ +// This file is part of the OpenStructure project <www.openstructure.org> +// +// Copyright (C) 2008-2010 by the OpenStructure authors +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation; either version 3.0 of the License, or (at your option) +// any later version. +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +//------------------------------------------------------------------------------ +#ifndef OST_SEQ_VIEWS_FROM_SEQUENCES_HH +#define OST_SEQ_VIEWS_FROM_SEQUENCES_HH + +#include <ost/seq/module_config.hh> +#include <ost/seq/alignment_handle.hh> + +namespace ost { namespace seq { + +std::pair<mol::EntityView, mol::EntityView> DLLEXPORT_OST_SEQ +ViewsFromSequences(const ConstSequenceHandle& seq1, + const ConstSequenceHandle& seq2); + +std::pair<mol::EntityView, mol::EntityView> DLLEXPORT_OST_SEQ +ViewsFromAlignment(const AlignmentHandle& aln, int index1=0, int index2=1); + +}} + +#endif diff --git a/modules/seq/base/tests/CMakeLists.txt b/modules/seq/base/tests/CMakeLists.txt index cb7025d94340ac0bc096c9747f8e879ac78cf5e9..528cb936ddae91eabe14d1b06c6aa743de7e29ac 100644 --- a/modules/seq/base/tests/CMakeLists.txt +++ b/modules/seq/base/tests/CMakeLists.txt @@ -1,5 +1,9 @@ set(OST_SEQ_UNIT_TESTS + test_seq.py test_sequence.cc + test_aligned_column.cc + test_aligned_region.cc + test_alignment.cc tests.cc ) diff --git a/modules/seq/base/tests/test_aligned_column.cc b/modules/seq/base/tests/test_aligned_column.cc new file mode 100644 index 0000000000000000000000000000000000000000..f76573df3c883f7f91b076442dae9900e0c5a42e --- /dev/null +++ b/modules/seq/base/tests/test_aligned_column.cc @@ -0,0 +1,133 @@ +//------------------------------------------------------------------------------ +// This file is part of the OpenStructure project <www.openstructure.org> +// +// Copyright (C) 2008-2010 by the OpenStructure authors +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation; either version 3.0 of the License, or (at your option) +// any later version. +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +//------------------------------------------------------------------------------ +#define BOOST_TEST_DYN_LINK +#include <boost/test/unit_test.hpp> + +#include <ost/mol/mol.hh> + +#include <ost/invalid_handle.hh> +#include <ost/integrity_error.hh> + +#include <ost/mol/mol.hh> +#include <ost/seq/alignment_handle.hh> +#include <ost/seq/aligned_region.hh> +#include <ost/seq/aligned_column.hh> +#include <ost/seq/sequence_handle.hh> +#include <ost/seq/sequence_list.hh> +#include <ost/seq/impl/sequence_list_impl.hh> +#include <ost/seq/impl/sequence_impl.hh> +#include <ost/seq/sequence_list.hh> + +using namespace ost; +using namespace ost::seq; +using namespace ost::mol; + + +struct Fixture { + Fixture() { + eh = CreateEntity(); + eh.SetName("TestEntity"); + XCSEditor e=eh.RequestXCSEditor(); + chain = e.InsertChain("A"); + res1 = e.AppendResidue(chain, "ARG"); + e.InsertAtom(res1, "CA",geom::Vec3(1,0,0)); + res2 = e.AppendResidue(chain, "ARG"); + e.InsertAtom(res2, "CA",geom::Vec3(0,1,0)); + res3 = e.AppendResidue(chain, "ARG"); + e.InsertAtom(res3, "CA",geom::Vec3(0,0,1)); + } + EntityHandle eh; + ChainHandle chain; + ResidueHandle res1; + ResidueHandle res2; + ResidueHandle res3; +}; + +BOOST_AUTO_TEST_SUITE( aligned_column ) + +BOOST_AUTO_TEST_CASE(aligned_column_triv) +{ + AlignedColumn ac =AlignedColumn(); + BOOST_CHECK_THROW(ac[0], InvalidHandle); + + AlignmentHandle a = CreateAlignment(); + SequenceHandle seq1 = CreateSequence("S1","ab-cdef"); + SequenceHandle seq2 = CreateSequence("S2","ghijk-l"); + a.AddSequence(seq1); + a.AddSequence(seq2); + AlignedRegion ar = AlignedRegion(a,1,3,1); + ac = ar[0]; + + BOOST_CHECK_EQUAL(ac.GetIndex(), 1); + ac = ar[1]; + BOOST_CHECK_EQUAL(ac.GetIndex(), 2); + BOOST_CHECK_THROW(ar[2], std::out_of_range); + BOOST_CHECK_THROW(ar[-1], std::out_of_range); + + AlignedColumn ac_test = AlignedColumn(a,2); + char c = ac[0]; + BOOST_CHECK_EQUAL(c, ac_test[0]); + BOOST_CHECK_EQUAL(c, '-'); + c = ac[1]; + BOOST_CHECK_EQUAL(c, ac_test[1]); + BOOST_CHECK_EQUAL(c, 'i'); +} + +BOOST_AUTO_TEST_CASE(aligned_get_residue) +{ + Fixture f; + EntityView v1 = f.eh.CreateFullView(); + EntityView v2 = f.eh.CreateFullView(); + + AlignmentHandle a = CreateAlignment(); + SequenceHandle seq1 = CreateSequence("S1","ab-cdef"); + SequenceHandle seq2 = CreateSequence("S2","ghijk-l"); + a.AddSequence(seq1); + a.AddSequence(seq2); + a.AttachView(0,v1); + a.AttachView(1,v2); + AlignedRegion ar = AlignedRegion(a,1,3,1); + AlignedColumn ac = ar[0]; + BOOST_CHECK_EQUAL(f.res2,ac.GetResidue(0)); + ac = ar[1]; + BOOST_CHECK_EQUAL(f.res2,ac.GetResidue(1)); + BOOST_CHECK_THROW(ac.GetResidue(2),std::out_of_range); + BOOST_CHECK_THROW(ac.GetResidue(-1),std::out_of_range); +} + +BOOST_AUTO_TEST_CASE(aligned_get_residue_index) +{ + AlignmentHandle a = CreateAlignment(); + SequenceHandle seq1 = CreateSequence("S1","ab-cdef"); + SequenceHandle seq2 = CreateSequence("S2","ghijk-l"); + a.AddSequence(seq1); + a.AddSequence(seq2); + AlignedRegion ar = AlignedRegion(a,1,3,1); + AlignedColumn ac = ar[0]; + BOOST_CHECK_EQUAL(ac.GetResidueIndex(0),1); + BOOST_CHECK_EQUAL(ac.GetResidueIndex(1),1); + + ac = ar[1]; + BOOST_CHECK_THROW(ac.GetResidueIndex(0),Error); + BOOST_CHECK_EQUAL(ac.GetResidueIndex(1),2); + BOOST_CHECK_THROW(ac.GetResidueIndex(2),std::out_of_range); + BOOST_CHECK_THROW(ac.GetResidueIndex(-1),std::out_of_range); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/modules/seq/base/tests/test_aligned_region.cc b/modules/seq/base/tests/test_aligned_region.cc new file mode 100644 index 0000000000000000000000000000000000000000..f22eb84bc82e5bf3ebfbc41991a5ef67851bbaf2 --- /dev/null +++ b/modules/seq/base/tests/test_aligned_region.cc @@ -0,0 +1,186 @@ +//------------------------------------------------------------------------------ +// This file is part of the OpenStructure project <www.openstructure.org> +// +// Copyright (C) 2008-2010 by the OpenStructure authors +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation; either version 3.0 of the License, or (at your option) +// any later version. +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +//------------------------------------------------------------------------------ +#define BOOST_TEST_DYN_LINK +#include <boost/test/unit_test.hpp> + +#include <ost/mol/mol.hh> + +#include <ost/invalid_handle.hh> +#include <ost/integrity_error.hh> + +#include <ost/mol/mol.hh> +#include <ost/seq/alignment_handle.hh> +#include <ost/seq/aligned_region.hh> +#include <ost/seq/sequence_handle.hh> +#include <ost/seq/sequence_list.hh> +#include <ost/seq/impl/sequence_list_impl.hh> +#include <ost/seq/impl/sequence_impl.hh> +#include <ost/seq/sequence_list.hh> + +using namespace ost; +using namespace ost::seq; +using namespace ost::mol; + + +BOOST_AUTO_TEST_SUITE( aligned_region ) + +BOOST_AUTO_TEST_CASE(aligned_region_triv) +{ + AlignmentHandle a = CreateAlignment(); + SequenceHandle seq1 = CreateSequence("S1","ab-cdef"); + SequenceHandle seq2 = CreateSequence("S2","ghijk-l"); + a.AddSequence(seq1); + a.AddSequence(seq2); + AlignedRegion ar = AlignedRegion(a,0,2,1); + BOOST_CHECK(ar.GetAlignmentHandle()==a); + BOOST_CHECK_EQUAL(ar.GetStart(),0); + BOOST_CHECK_EQUAL(ar.GetEnd(),2); + BOOST_CHECK_EQUAL(ar.GetLength(),2); + BOOST_CHECK_EQUAL(ar.GetMaster(),1); + ar.SetMaster(0); + BOOST_CHECK_EQUAL(ar.GetMaster(),0); + ar.SetMaster(-1); + BOOST_CHECK_EQUAL(ar.GetMaster(),-1); + BOOST_CHECK_THROW(ar.SetMaster(2),IntegrityError); + BOOST_CHECK_THROW(ar.SetMaster(-2),IntegrityError); + + AlignedRegion ar_same = a.MakeRegion(0,2); + BOOST_CHECK(ar==ar_same); +} + +BOOST_AUTO_TEST_CASE(aligned_region_delete) +{ + AlignmentHandle a = CreateAlignment(); + SequenceHandle seq1 = CreateSequence("S1","ab-cdef"); + SequenceHandle seq2 = CreateSequence("S2","ghijk-l"); + a.AddSequence(seq1); + a.AddSequence(seq2); + AlignedRegion ar = a.MakeRegion(1,2); + ar.Delete(); + BOOST_CHECK_EQUAL(a.GetSequence(0).GetString(),"acdef"); + BOOST_CHECK_EQUAL(a.GetSequence(1).GetString(),"gjk-l"); + + a = CreateAlignment(); + seq1 = CreateSequence("S1","ab-cdef"); + seq2 = CreateSequence("S2","ghijk-l"); + a.AddSequence(seq1); + a.AddSequence(seq2); + ar = a.MakeRegion(0,7); + ar.Delete(); + BOOST_CHECK_EQUAL(a.GetSequence(0).GetString(),""); + BOOST_CHECK_EQUAL(a.GetSequence(1).GetString(),""); + + a = CreateAlignment(); + seq1 = CreateSequence("S1","ab-cdef"); + seq2 = CreateSequence("S2","ghijk-l"); + a.AddSequence(seq1); + a.AddSequence(seq2); + ar = a.MakeRegion(0,0); + ar.Delete(); + BOOST_CHECK_EQUAL(a.GetSequence(0).GetString(),"ab-cdef"); + BOOST_CHECK_EQUAL(a.GetSequence(1).GetString(),"ghijk-l"); +} + +BOOST_AUTO_TEST_CASE(aligned_region_replace) +{ + AlignmentHandle a1 = CreateAlignment(); + SequenceHandle seq11 = CreateSequence("S1","ab-cdef"); + SequenceHandle seq12 = CreateSequence("S2","ghijk-l"); + a1.AddSequence(seq11); + a1.AddSequence(seq12); + AlignedRegion ar1 = a1.MakeRegion(2,2); + AlignmentHandle a2 = CreateAlignment(); + SequenceHandle seq21 = CreateSequence("S1","zzzzzzz"); + SequenceHandle seq22 = CreateSequence("S2","ee-----"); + a2.AddSequence(seq21); + a2.AddSequence(seq22); + AlignedRegion ar2 = a2.MakeRegion(2,2); + ar1.Replace(ar2); + BOOST_CHECK_EQUAL(a1.GetSequence(0).GetString(),"abzzdef"); + BOOST_CHECK_EQUAL(a1.GetSequence(1).GetString(),"gh--k-l"); + + a1 = CreateAlignment(); + seq11 = CreateSequence("S1","ab-cdef"); + seq12 = CreateSequence("S2","ghijk-l"); + a1.AddSequence(seq11); + a1.AddSequence(seq12); + ar1 = a1.MakeRegion(1,2); + a2 = CreateAlignment(); + seq21 = CreateSequence("S1","zzzzzzz"); + seq22 = CreateSequence("S2","ee-----"); + a2.AddSequence(seq21); + a2.AddSequence(seq22); + ar2 = a2.MakeRegion(1,0); + ar1.Replace(ar2); + BOOST_CHECK_EQUAL(a1.GetSequence(0).GetString(),"acdef"); + BOOST_CHECK_EQUAL(a1.GetSequence(1).GetString(),"gjk-l"); + + a1 = CreateAlignment(); + seq11 = CreateSequence("S1","ab-cdef"); + seq12 = CreateSequence("S2","ghijk-l"); + a1.AddSequence(seq11); + a1.AddSequence(seq12); + ar1 = a1.MakeRegion(1,2); + a2 = CreateAlignment(); + seq21 = CreateSequence("S1","zzzzzzz"); + seq22 = CreateSequence("S2","ee-----"); + a2.AddSequence(seq21); + a2.AddSequence(seq22); + ar2 = a2.MakeRegion(1,3); + ar1.Replace(ar2); + BOOST_CHECK_EQUAL(a1.GetSequence(0).GetString(),"azzzcdef"); + BOOST_CHECK_EQUAL(a1.GetSequence(1).GetString(),"ge--jk-l"); +} + +BOOST_AUTO_TEST_CASE(aligned_region_shift) +{ + AlignmentHandle a = CreateAlignment(); + SequenceHandle seq1 = CreateSequence("S1","ab-c"); + SequenceHandle seq2 = CreateSequence("S2","ghij"); + a.AddSequence(seq1); + a.AddSequence(seq2); + AlignedRegion ar = a.MakeRegion(1,2); + + BOOST_CHECK_NO_THROW(ar.ShiftLeft(1)); + BOOST_CHECK_EQUAL(ar.GetStart(),0); + BOOST_CHECK_EQUAL(ar.GetEnd(),2); + BOOST_CHECK_EQUAL(ar.GetLength(),2); + BOOST_CHECK_EQUAL(a.GetSequence(0).GetString(),"b-ac"); + BOOST_CHECK_EQUAL(a.GetSequence(1).GetString(),"higj"); + BOOST_CHECK_NO_THROW(ar.ShiftLeft(0)); + BOOST_CHECK_EQUAL(a.GetSequence(0).GetString(),"b-ac"); + BOOST_CHECK_EQUAL(a.GetSequence(1).GetString(),"higj"); + + BOOST_CHECK_THROW(ar.ShiftLeft(1),IntegrityError); + + BOOST_CHECK_NO_THROW(ar.ShiftRight(2)); + BOOST_CHECK_EQUAL(ar.GetStart(),2); + BOOST_CHECK_EQUAL(ar.GetEnd(),4); + BOOST_CHECK_EQUAL(ar.GetLength(),2); + BOOST_CHECK_EQUAL(a.GetSequence(0).GetString(),"acb-"); + BOOST_CHECK_EQUAL(a.GetSequence(1).GetString(),"gjhi"); + + BOOST_CHECK_NO_THROW(ar.ShiftRight(0)); + BOOST_CHECK_EQUAL(a.GetSequence(0).GetString(),"acb-"); + BOOST_CHECK_EQUAL(a.GetSequence(1).GetString(),"gjhi"); + + BOOST_CHECK_THROW(ar.ShiftRight(1),IntegrityError); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/modules/seq/base/tests/test_alignment.cc b/modules/seq/base/tests/test_alignment.cc new file mode 100644 index 0000000000000000000000000000000000000000..260ea5c235a27b3977731f7dab778c27d915b5ec --- /dev/null +++ b/modules/seq/base/tests/test_alignment.cc @@ -0,0 +1,223 @@ +//------------------------------------------------------------------------------ +// This file is part of the OpenStructure project <www.openstructure.org> +// +// Copyright (C) 2008-2010 by the OpenStructure authors +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation; either version 3.0 of the License, or (at your option) +// any later version. +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +//------------------------------------------------------------------------------ +#define BOOST_TEST_DYN_LINK +#include <boost/test/unit_test.hpp> + +#include <ost/invalid_handle.hh> +#include <ost/mol/mol.hh> +#include <ost/seq/alignment_handle.hh> +#include <ost/seq/aligned_region.hh> +#include <ost/seq/sequence_handle.hh> +#include <ost/seq/sequence_list.hh> +#include <ost/seq/impl/sequence_list_impl.hh> +#include <ost/seq/impl/sequence_impl.hh> +#include <ost/seq/sequence_list.hh> + +using namespace ost; +using namespace ost::seq; +using namespace ost::mol; + + +struct Fixture { + Fixture() { + eh = CreateEntity(); + eh.SetName("TestEntity"); + XCSEditor e=eh.RequestXCSEditor(); + chain = e.InsertChain("A"); + res1 = e.AppendResidue(chain, "ARG"); + e.InsertAtom(res1, "CA",geom::Vec3(1,0,0)); + res2 = e.AppendResidue(chain, "ARG"); + e.InsertAtom(res2, "CA",geom::Vec3(0,1,0)); + res3 = e.AppendResidue(chain, "ARG"); + e.InsertAtom(res3, "CA",geom::Vec3(0,0,1)); + } + EntityHandle eh; + ChainHandle chain; + ResidueHandle res1; + ResidueHandle res2; + ResidueHandle res3; +}; + +BOOST_AUTO_TEST_SUITE( alignment ) + +BOOST_AUTO_TEST_CASE(alignment_triv) +{ + AlignmentHandle a; + BOOST_CHECK_THROW(a.AddSequence(CreateSequence("S1","-asdf-")),InvalidHandle); + a = CreateAlignment(); + BOOST_CHECK_NO_THROW(a.AddSequence(CreateSequence("S1","-asdf-"))); + BOOST_CHECK_THROW(a.AddSequence(SequenceHandle()),InvalidSequence); + BOOST_CHECK_THROW(a.AddSequence(CreateSequence("S2","-asdf-f")),InvalidSequence); + SequenceList list = CreateSequenceList(); + list.AddSequence(CreateSequence("S1", "-asdf-")); + list.AddSequence(CreateSequence("S2", "fasdfas")); + BOOST_CHECK_THROW(AlignmentFromSequenceList(list),InvalidAlignment); + list = CreateSequenceList(); + list.AddSequence(CreateSequence("S1", "-asdf-")); + list.AddSequence(CreateSequence("S2", "fasdfa")); + BOOST_CHECK_NO_THROW(AlignmentFromSequenceList(list)); +} + +BOOST_AUTO_TEST_CASE(alignment_count_and_length) +{ + AlignmentHandle a = CreateAlignment(); + BOOST_CHECK_EQUAL(a.GetCount(),0); + BOOST_CHECK_EQUAL(a.GetLength(),0); + a.AddSequence(CreateSequence("S1","asdf")); + BOOST_CHECK_EQUAL(a.GetCount(),1); + BOOST_CHECK_EQUAL(a.GetLength(),4); + a.AddSequence(CreateSequence("S2","qwer")); + BOOST_CHECK_EQUAL(a.GetCount(),2); + BOOST_CHECK_EQUAL(a.GetLength(),4); +} + +BOOST_AUTO_TEST_CASE(alignment_onelettercode) +{ + AlignmentHandle a = CreateAlignment(); + SequenceHandle seq1 = CreateSequence("S1","-a-sdf"); + SequenceHandle seq2 = CreateSequence("S2","q--wer"); + a.AddSequence(seq1); + a.AddSequence(seq2); + BOOST_CHECK_EQUAL(a.GetOneLetterCode(0,0),'-'); + BOOST_CHECK_EQUAL(a.GetOneLetterCode(0,0),seq1.GetOneLetterCode(0)); + BOOST_CHECK_EQUAL(a.GetOneLetterCode(1,0),'q'); + BOOST_CHECK_EQUAL(a.GetOneLetterCode(1,0),seq2.GetOneLetterCode(0)); + BOOST_CHECK_EQUAL(a.GetOneLetterCode(0,3),'s'); + BOOST_CHECK_EQUAL(a.GetOneLetterCode(0,3),seq1.GetOneLetterCode(3)); + BOOST_CHECK_EQUAL(a.GetOneLetterCode(1,3),'w'); + BOOST_CHECK_EQUAL(a.GetOneLetterCode(1,3),seq2.GetOneLetterCode(3)); + BOOST_CHECK_THROW(a.GetOneLetterCode(0,-1),Error); + BOOST_CHECK_THROW(a.GetOneLetterCode(1,6),Error); + BOOST_CHECK_THROW(a.GetOneLetterCode(2,0),Error); + BOOST_CHECK_THROW(a.GetOneLetterCode(-1,0),Error); +} + +BOOST_AUTO_TEST_CASE(alignment_pos_and_index) +{ + AlignmentHandle a = CreateAlignment(); + a.AddSequence(CreateSequence("S1","-a-sdf")); + a.AddSequence(CreateSequence("S2","q--wer")); + BOOST_CHECK_EQUAL(a.GetPos(0,1), 3); + BOOST_CHECK_EQUAL(a.GetResidueIndex(0,3), 1); + BOOST_CHECK_EQUAL(a.GetPos(1,2), 4); + BOOST_CHECK_EQUAL(a.GetResidueIndex(1,4), 2); + BOOST_CHECK_THROW(a.GetPos(0,-1),Error); + BOOST_CHECK_THROW(a.GetPos(1,4),Error); + BOOST_CHECK_THROW(a.GetPos(2,0),Error); + BOOST_CHECK_THROW(a.GetPos(-1,0),Error); +} + +BOOST_AUTO_TEST_CASE(alignment_getseq) +{ + AlignmentHandle a = CreateAlignment(); + SequenceHandle seq1 = CreateSequence("S1","-a-sdf"); + SequenceHandle seq2 = CreateSequence("S2","q--wer"); + a.AddSequence(seq1); + a.AddSequence(seq2); + BOOST_CHECK_EQUAL(a.GetSequence(0), seq1); + BOOST_CHECK_EQUAL(a.GetSequence(1), seq2); + BOOST_CHECK_THROW(a.GetSequence(-1), Error); + BOOST_CHECK_THROW(a.GetSequence(2), Error); +} + +BOOST_AUTO_TEST_CASE(alignment_attach_view) +{ + Fixture f; + EntityView v = f.eh.CreateFullView(); + EntityView v2 = f.eh.CreateFullView(); + + AlignmentHandle a = CreateAlignment(); + SequenceHandle seq1 = CreateSequence("S1","r-r"); + SequenceHandle seq2 = CreateSequence("S2","aa-"); + a.AddSequence(seq1); + a.AddSequence(seq2); + a.AttachView(0,v); + a.AttachView(1,v2); + BOOST_CHECK_EQUAL(a.GetResidue(0,0), f.res1); + BOOST_CHECK_EQUAL(a.GetResidue(0,2), f.res3); + BOOST_CHECK_EQUAL(a.GetResidue(1,0), f.res1); + BOOST_CHECK_EQUAL(a.GetResidue(1,1), f.res2); + BOOST_CHECK_NO_THROW(a.AttachView(0,EntityView())); + BOOST_CHECK_EQUAL(a.GetResidue(0,1), EntityView()); + BOOST_CHECK_EQUAL(a.GetResidue(0,3), EntityView()); + BOOST_CHECK_THROW(a.GetResidue(-1,0),Error) +} + +BOOST_AUTO_TEST_CASE(alignment_cut) +{ + AlignmentHandle a = CreateAlignment(); + SequenceHandle seq1 = CreateSequence("S1","r-r"); + SequenceHandle seq2 = CreateSequence("S2","aa-"); + a.AddSequence(seq1); + a.AddSequence(seq2); + a.Cut(1,2); + BOOST_CHECK_EQUAL(a.GetLength(),2); + BOOST_CHECK_EQUAL(a.GetOneLetterCode(0,0),'r'); + BOOST_CHECK_EQUAL(a.GetOneLetterCode(0,1),'r'); + BOOST_CHECK_THROW(a.GetOneLetterCode(0,2),Error); + BOOST_CHECK_EQUAL(a.GetOneLetterCode(1,0),'a'); + BOOST_CHECK_EQUAL(a.GetOneLetterCode(1,1),'-'); + BOOST_CHECK_THROW(a.GetOneLetterCode(1,2),Error); +} + +BOOST_AUTO_TEST_CASE(alignment_shift_region) +{ + AlignmentHandle a = CreateAlignment(); + SequenceHandle seq1 = CreateSequence("S1","abcdef"); + SequenceHandle seq2 = CreateSequence("S2","ghijkl"); + a.AddSequence(seq1); + a.AddSequence(seq2); + a.ShiftRegion(2, 4, 2); + BOOST_CHECK_EQUAL(a.GetSequence(0).GetString(),"abefcd"); + BOOST_CHECK_EQUAL(a.GetSequence(1).GetString(),"ghklij"); + + a.ShiftRegion(2, 2, 2);//Shift nothing + BOOST_CHECK_EQUAL(a.GetSequence(0).GetString(),"abefcd"); + + a.ShiftRegion(2,3,1,1); + BOOST_CHECK_EQUAL(a.GetSequence(0).GetString(),"abefcd"); + BOOST_CHECK_EQUAL(a.GetSequence(1).GetString(),"ghlkij"); + + BOOST_CHECK_THROW(a.ShiftRegion(0,2,1,2),Error); + BOOST_CHECK_THROW(a.ShiftRegion(0,2,1,-2),Error); + + BOOST_CHECK_THROW(a.ShiftRegion(0,2,-1),std::out_of_range); + BOOST_CHECK_THROW(a.ShiftRegion(0,5,2),std::out_of_range); +} + +BOOST_AUTO_TEST_CASE(alignment_aligned_region) +{ + AlignmentHandle a = CreateAlignment(); + SequenceHandle seq1 = CreateSequence("S1","abcdef"); + SequenceHandle seq2 = CreateSequence("S2","ghijkl"); + a.AddSequence(seq1); + a.AddSequence(seq2); + AlignedRegion ar = a.MakeRegion(1,2); + BOOST_CHECK_EQUAL(ar.GetLength(),2); + BOOST_CHECK_EQUAL(ar.GetStart(),1); + BOOST_CHECK_EQUAL(ar.GetEnd(),3); + + BOOST_CHECK_THROW(ar = a.MakeRegion(-1,2,0),std::out_of_range); + BOOST_CHECK_THROW(ar = a.MakeRegion(0,7,0),std::out_of_range); + BOOST_CHECK_NO_THROW(ar = a.MakeRegion(2,4,0)); + BOOST_CHECK_NO_THROW(ar = a.MakeRegion(3,2,0)); + BOOST_CHECK_NO_THROW(ar = a.MakeRegion(3,3,0)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/modules/seq/base/tests/test_seq.py b/modules/seq/base/tests/test_seq.py new file mode 100644 index 0000000000000000000000000000000000000000..4eed73b1132f82109cc0250807561cb0675db3c0 --- /dev/null +++ b/modules/seq/base/tests/test_seq.py @@ -0,0 +1,127 @@ +import unittest +from ost import * +from ost import settings +from ost import seq + + +def fixture(): + e=mol.CreateEntity() + ede=e.RequestXCSEditor() + chain=ede.InsertChain('A') + for res in 'ABCDEFGH': + r=ede.AppendResidue(chain, res) + r.SetOneLetterCode(res) + ede.InsertAtom(r, "XXX", geom.Vec3()) + + return e + +class TestSeq(unittest.TestCase): + + def setUp(self): + self.ent=fixture() + + def testViewsFromSequences_01(self): + seq_a=seq.CreateSequence("A", "ABCD-FGH") + seq_a.AttachView(self.ent.Select('rname=A,B,C,D,F,G,H')) + seq_b=seq.CreateSequence("B", "ABCDEFGH") + seq_b.AttachView(self.ent.Select('')) + a, b=seq.ViewsFromSequences(seq_a, seq_b) + string_a=''.join([r.one_letter_code for r in a.residues]) + string_b=''.join([r.one_letter_code for r in b.residues]) + self.assertEqual(string_a, 'ABCDFGH') + self.assertEqual(string_b, 'ABCDFGH') + + def testViewsFromSequences_02(self): + seq_a=seq.CreateSequence("A", "ABCD-FGH") + seq_a.AttachView(self.ent.Select('rname=A,B,C,D,F,G,H')) + seq_b=seq.CreateSequence("B", "ABCD-FGH") + seq_b.AttachView(self.ent.Select('rname=A,B,C,D,F,G,H')) + a, b=seq.ViewsFromSequences(seq_a, seq_b) + string_a=''.join([r.one_letter_code for r in a.residues]) + string_b=''.join([r.one_letter_code for r in b.residues]) + self.assertEqual(string_a, 'ABCDFGH') + self.assertEqual(string_b, 'ABCDFGH') + + def testViewsFromSequences_03(self): + seq_a=seq.CreateSequence("A", "ABCD--GH") + seq_a.AttachView(self.ent.Select('rname=A,B,C,D,G,H')) + seq_b=seq.CreateSequence("B", "ABCD-FGH") + seq_b.AttachView(self.ent.Select('rname=A,B,C,D,F,G,H')) + a, b=seq.ViewsFromSequences(seq_a, seq_b) + string_a=''.join([r.one_letter_code for r in a.residues]) + string_b=''.join([r.one_letter_code for r in b.residues]) + self.assertEqual(string_a, 'ABCDGH') + self.assertEqual(string_b, 'ABCDGH') + + def testViewsFromSequences_04(self): + seq_a=seq.CreateSequence("A", "ABCD-FGH") + seq_a.AttachView(self.ent.Select('rname=A,B,C,D,F,G,H')) + seq_b=seq.CreateSequence("B", "ABCD--GH") + seq_b.AttachView(self.ent.Select('rname=A,B,C,D,G,H')) + a, b=seq.ViewsFromSequences(seq_a, seq_b) + string_a=''.join([r.one_letter_code for r in a.residues]) + string_b=''.join([r.one_letter_code for r in b.residues]) + self.assertEqual(string_a, 'ABCDGH') + self.assertEqual(string_b, 'ABCDGH') + + def testViewsFromSequences_05(self): + seq_a=seq.CreateSequence("A", "ABCD-F--") + seq_a.AttachView(self.ent.Select('rname=A,B,C,D,F')) + seq_b=seq.CreateSequence("B", "ABCDEFGH") + seq_b.AttachView(self.ent.Select('rname=A,B,C,D,E,F,G,H')) + a, b=seq.ViewsFromSequences(seq_a, seq_b) + string_a=''.join([r.one_letter_code for r in a.residues]) + string_b=''.join([r.one_letter_code for r in b.residues]) + self.assertEqual(string_a, 'ABCDF') + self.assertEqual(string_b, 'ABCDF') + + def testViewsFromSequences_06(self): + seq_a=seq.CreateSequence("A", "--CD-FGH") + seq_a.AttachView(self.ent.Select('rname=C,D,F,G,H')) + seq_b=seq.CreateSequence("B", "ABCDEFGH") + seq_b.AttachView(self.ent.Select('rname=A,B,C,D,E,F,G,H')) + a, b=seq.ViewsFromSequences(seq_a, seq_b) + string_a=''.join([r.one_letter_code for r in a.residues]) + string_b=''.join([r.one_letter_code for r in b.residues]) + self.assertEqual(string_a, 'CDFGH') + self.assertEqual(string_b, 'CDFGH') + + + def testViewsFromSequences_07(self): + seq_a=seq.CreateSequence("A", "AB-D-FGH") + seq_a.AttachView(self.ent.Select('rname=A,B,D,F,G,H')) + seq_b=seq.CreateSequence("B", "AB-DEF-H") + seq_b.AttachView(self.ent.Select('rname=A,B,D,E,F,H')) + a, b=seq.ViewsFromSequences(seq_a, seq_b) + string_a=''.join([r.one_letter_code for r in a.residues]) + string_b=''.join([r.one_letter_code for r in b.residues]) + self.assertEqual(string_a, 'ABDFH') + self.assertEqual(string_b, 'ABDFH') + + + def testViewsFromSequences_08(self): + seq_a=seq.CreateSequence("A", "A-C-E-G") + seq_a.AttachView(self.ent.Select('rname=A,C,E,G')) + seq_b=seq.CreateSequence("B", "-B-D-H-") + seq_b.AttachView(self.ent.Select('rname=B,D,H')) + a, b=seq.ViewsFromSequences(seq_a, seq_b) + string_a=''.join([r.one_letter_code for r in a.residues]) + string_b=''.join([r.one_letter_code for r in b.residues]) + self.assertEqual(string_a, '') + self.assertEqual(string_b, '') + + def testViewsFromSequences_09(self): + seq_a=seq.CreateSequence("A", "B-D-FGH") + seq_a.AttachView(self.ent.Select('rname=A,B,D,F,G,H')) + seq_a.SetSequenceOffset(1) + seq_b=seq.CreateSequence("B", "B-DEF-H") + seq_b.SetSequenceOffset(1) + seq_b.AttachView(self.ent.Select('rname=A,B,D,E,F,H')) + a, b=seq.ViewsFromSequences(seq_a, seq_b) + string_a=''.join([r.one_letter_code for r in a.residues]) + string_b=''.join([r.one_letter_code for r in b.residues]) + self.assertEqual(string_a, 'BDFH') + self.assertEqual(string_b, 'BDFH') +suite = unittest.TestLoader().loadTestsFromTestCase(TestSeq) +unittest.TextTestRunner().run(suite) + diff --git a/modules/seq/base/tests/test_sequence.cc b/modules/seq/base/tests/test_sequence.cc index 666ebe6c49610d07ee93f39664d92d5b3be04abe..97997f9156c63ed1b31a098f405570c02f5da084 100644 --- a/modules/seq/base/tests/test_sequence.cc +++ b/modules/seq/base/tests/test_sequence.cc @@ -19,12 +19,36 @@ #define BOOST_TEST_DYN_LINK #include <boost/test/unit_test.hpp> +#include <ost/mol/mol.hh> + #include <ost/seq/sequence_handle.hh> #include <ost/seq/invalid_sequence.hh> #include <ost/seq/sequence_op.hh> using namespace ost; using namespace ost::seq; +using namespace ost::mol; + + +struct Fixture { + Fixture() { + eh = CreateEntity(); + eh.SetName("TestEntity"); + XCSEditor e=eh.RequestXCSEditor(); + chain = e.InsertChain("A"); + res1 = e.AppendResidue(chain, "ARG"); + e.InsertAtom(res1, "CA",geom::Vec3(1,0,0)); + res2 = e.AppendResidue(chain, "ARG"); + e.InsertAtom(res2, "CA",geom::Vec3(0,1,0)); + res3 = e.AppendResidue(chain, "ARG"); + e.InsertAtom(res3, "CA",geom::Vec3(0,0,1)); + } + EntityHandle eh; + ChainHandle chain; + ResidueHandle res1; + ResidueHandle res2; + ResidueHandle res3; +}; BOOST_AUTO_TEST_SUITE( seq ) @@ -34,18 +58,64 @@ BOOST_AUTO_TEST_CASE(seq_triv) BOOST_CHECK_THROW(CreateSequence("S1", "1"), InvalidSequence); BOOST_CHECK_THROW(CreateSequence("S1", "."), InvalidSequence); BOOST_CHECK_THROW(CreateSequence("S1", " "), InvalidSequence); + SequenceHandle s=CreateSequence("S1","-afbcdefghijkLMNOPQRSTUV-"); + BOOST_CHECK_EQUAL(s.GetString(),"-afbcdefghijkLMNOPQRSTUV-"); + BOOST_CHECK_NO_THROW(s.SetString("-afc--de-f")); + BOOST_CHECK_EQUAL(s.GetString(),"-afc--de-f"); + BOOST_CHECK_THROW(s.SetString("1"), InvalidSequence); +} + +BOOST_AUTO_TEST_CASE(seq_length) +{ + SequenceHandle s=CreateSequence("S1", "abfcdadeaf"); + BOOST_CHECK_EQUAL(s.GetLength(),10); + s=CreateSequence("S1", "-afc--de-f"); + BOOST_CHECK_EQUAL(s.GetLength(),10); + s=CreateSequence("S1", ""); + BOOST_CHECK_EQUAL(s.GetLength(),0); +} + +BOOST_AUTO_TEST_CASE(seq_string) +{ + SequenceHandle s=CreateSequence("S1", "abfcdadeaf"); + BOOST_CHECK_EQUAL(s.GetString(),"abfcdadeaf"); + BOOST_CHECK_EQUAL(s.GetGaplessString(),"abfcdadeaf"); + s=CreateSequence("S1", "-afc--de-f"); + BOOST_CHECK_EQUAL(s.GetString(),"-afc--de-f"); + BOOST_CHECK_EQUAL(s.GetGaplessString(),"afcdef"); + s=CreateSequence("S1", ""); + BOOST_CHECK_EQUAL(s.GetString(),""); + BOOST_CHECK_EQUAL(s.GetGaplessString(),""); +} + +BOOST_AUTO_TEST_CASE(seq_onelettercode) +{ + SequenceHandle s=CreateSequence("S1", "abfcdadeaf"); + BOOST_CHECK_EQUAL(s.GetOneLetterCode(0),'a'); + BOOST_CHECK_EQUAL(s.GetOneLetterCode(3),'c'); + BOOST_CHECK_EQUAL(s.GetOneLetterCode(9),'f'); + BOOST_CHECK_THROW(s.GetOneLetterCode(-1),Error); + BOOST_CHECK_THROW(s.GetOneLetterCode(10),Error); + s=CreateSequence("S1", "-afc--de-f"); + BOOST_CHECK_EQUAL(s.GetOneLetterCode(0),'-'); + BOOST_CHECK_EQUAL(s.GetOneLetterCode(1),'a'); + BOOST_CHECK_EQUAL(s.GetOneLetterCode(9),'f'); + BOOST_CHECK_THROW(s.GetOneLetterCode(-1),Error); + BOOST_CHECK_THROW(s.GetOneLetterCode(10),Error); + s=CreateSequence("S1", ""); + BOOST_CHECK_THROW(s.GetOneLetterCode(0),Error); } BOOST_AUTO_TEST_CASE(seq_getnum) { SequenceHandle s=CreateSequence("S1", "-afc--de-f"); BOOST_CHECK_THROW(s.GetResidueIndex(0), Error); - BOOST_CHECK(s.GetResidueIndex(1)==1-1); - BOOST_CHECK(s.GetResidueIndex(2)==2-1); - BOOST_CHECK(s.GetResidueIndex(3)==3-1); - BOOST_CHECK(s.GetResidueIndex(6)==4-1); - BOOST_CHECK(s.GetResidueIndex(7)==5-1); - BOOST_CHECK(s.GetResidueIndex(9)==6-1); + BOOST_CHECK_EQUAL(s.GetResidueIndex(1),1-1); + BOOST_CHECK_EQUAL(s.GetResidueIndex(2),2-1); + BOOST_CHECK_EQUAL(s.GetResidueIndex(3),3-1); + BOOST_CHECK_EQUAL(s.GetResidueIndex(6),4-1); + BOOST_CHECK_EQUAL(s.GetResidueIndex(7),5-1); + BOOST_CHECK_EQUAL(s.GetResidueIndex(9),6-1); BOOST_CHECK_THROW(s.GetResidueIndex(-1), Error); BOOST_CHECK_THROW(s.GetResidueIndex(10), Error); } @@ -62,4 +132,85 @@ BOOST_AUTO_TEST_CASE(seq_getpos) BOOST_CHECK(s.GetPos(5)==9); } +BOOST_AUTO_TEST_CASE(seq_offset) +{ + SequenceHandle s=CreateSequence("S1", "-afc--de-f"); + SequenceHandle s2=CreateSequence("S1", "-afc--de-f"); + s.SetSequenceOffset(2); + BOOST_CHECK_THROW(s.GetPos(-1), Error); + BOOST_CHECK_THROW(s.GetPos(0), Error); + BOOST_CHECK_THROW(s.GetPos(1), Error); + BOOST_CHECK_EQUAL(s.GetPos(2),1); + BOOST_CHECK_EQUAL(s.GetPos(2),s2.GetPos(2-2)); + BOOST_CHECK_EQUAL(s.GetPos(5),6); + BOOST_CHECK_EQUAL(s.GetPos(5),s2.GetPos(5-2)); + BOOST_CHECK_EQUAL(s.GetPos(7),9); + BOOST_CHECK_EQUAL(s.GetPos(7),s2.GetPos(7-2)); + BOOST_CHECK_THROW(s.GetPos(8), Error); + BOOST_CHECK_THROW(s.GetResidueIndex(0), Error); + BOOST_CHECK_EQUAL(s.GetResidueIndex(1),2); + BOOST_CHECK_EQUAL(s.GetResidueIndex(1),s2.GetResidueIndex(1)+2); + BOOST_CHECK_EQUAL(s.GetResidueIndex(6), 5); + BOOST_CHECK_EQUAL(s.GetResidueIndex(6),s2.GetResidueIndex(6)+2); + BOOST_CHECK_THROW(s.GetResidueIndex(10), Error); + + s.SetSequenceOffset(-1); + BOOST_CHECK_THROW(s.GetPos(-2), Error); + BOOST_CHECK_EQUAL(s.GetPos(-1), 1); + BOOST_CHECK_EQUAL(s.GetPos(0), 2); + BOOST_CHECK_EQUAL(s.GetPos(0),s2.GetPos(0+1)); + BOOST_CHECK_EQUAL(s.GetPos(2), 6); + BOOST_CHECK_EQUAL(s.GetPos(2),s2.GetPos(2+1)); + BOOST_CHECK_EQUAL(s.GetPos(4),9); + BOOST_CHECK_EQUAL(s.GetPos(4),s2.GetPos(4+1)); + BOOST_CHECK_THROW(s.GetPos(5), Error); + BOOST_CHECK_THROW(s.GetResidueIndex(0), Error); + BOOST_CHECK_EQUAL(s.GetResidueIndex(1),-1); + BOOST_CHECK_EQUAL(s.GetResidueIndex(1),s2.GetResidueIndex(1)-1); + BOOST_CHECK_EQUAL(s.GetResidueIndex(6), 2); + BOOST_CHECK_EQUAL(s.GetResidueIndex(6),s2.GetResidueIndex(6)-1); + BOOST_CHECK_THROW(s.GetResidueIndex(10), Error); +} + +BOOST_AUTO_TEST_CASE(seq_gaps) +{ + SequenceHandle s=CreateSequence("S1", ""); + BOOST_CHECK_EQUAL(s.GetFirstNonGap(),-1); + BOOST_CHECK_EQUAL(s.GetLastNonGap(),-1); + + s=CreateSequence("S1", "afcdef"); + BOOST_CHECK_EQUAL(s.GetFirstNonGap(),0); + BOOST_CHECK_EQUAL(s.GetLastNonGap(),5); + + s=CreateSequence("S1", "-afc--de-f-"); + BOOST_CHECK_EQUAL(s.GetFirstNonGap(),1); + BOOST_CHECK_EQUAL(s.GetLastNonGap(),9); +} + +BOOST_AUTO_TEST_CASE(seq_attach_view) +{ + Fixture f; + SequenceHandle s=CreateSequence("S1", "r-r"); + BOOST_CHECK_EQUAL(s.HasAttachedView(),false); + BOOST_CHECK_EQUAL(s.GetAttachedView(),EntityView()); + BOOST_CHECK_EQUAL(s.GetResidue(0),ResidueHandle()); + + EntityView v = f.eh.CreateFullView(); + s.AttachView(v); + BOOST_CHECK_EQUAL(s.HasAttachedView(),true); + BOOST_CHECK_EQUAL(s.GetAttachedView(),v); + + BOOST_CHECK_EQUAL(s.GetResidue(0),f.res1); + BOOST_CHECK_EQUAL(s.GetResidue(s.GetPos(0)),f.res1); + BOOST_CHECK_EQUAL(s.GetResidue(1),ResidueHandle()); + BOOST_CHECK_EQUAL(s.GetResidue(2),f.res3); + BOOST_CHECK_EQUAL(s.GetResidue(s.GetPos(1)),f.res3); + + v = EntityView(); + s.AttachView(v); + BOOST_CHECK_EQUAL(s.HasAttachedView(),false); + BOOST_CHECK_EQUAL(s.GetAttachedView(),EntityView()); + BOOST_CHECK_EQUAL(s.GetResidue(0),ResidueHandle()); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/modules/seq/base/tests/testfiles/testprotein.pdb b/modules/seq/base/tests/testfiles/testprotein.pdb new file mode 100644 index 0000000000000000000000000000000000000000..e7733fdb8a272ad98f1d125cc1076d8a1e526234 --- /dev/null +++ b/modules/seq/base/tests/testfiles/testprotein.pdb @@ -0,0 +1,15 @@ +ATOM 1 CA MET A 1 20.601 35.494 57.793 1.00 41.58 C +ATOM 2 CA ARG A 2 19.396 31.903 58.033 1.00 34.35 C +ATOM 3 CA LEU A 3 18.330 32.402 61.664 1.00 34.70 C +ATOM 4 CA ASP A 4 17.099 35.980 61.411 1.00 37.42 C +ATOM 5 CA GLY A 5 15.027 37.141 64.378 1.00 40.00 C +ATOM 6 CA LYS A 6 15.354 33.938 66.391 1.00 38.75 C +ATOM 7 CA THR A 7 16.484 33.152 69.925 1.00 31.14 C +ATOM 8 CA ALA A 8 18.759 30.274 70.854 1.00 29.72 C +ATOM 9 CA LEU A 9 19.784 28.923 74.261 1.00 26.72 C +ATOM 10 CA ILE A 10 23.077 27.016 74.090 1.00 24.46 C +ATOM 11 CA THR A 11 24.256 25.247 77.240 1.00 28.56 C +ATOM 12 CA GLY A 12 27.934 25.121 78.150 1.00 29.86 C +ATOM 13 CA SER A 13 28.721 27.662 75.443 1.00 33.66 C +ATOM 14 CA ALA A 14 31.320 29.688 77.335 1.00 36.95 C +ATOM 15 CA ARG A 15 34.025 27.749 75.511 1.00 38.19 C diff --git a/scripts/init.py b/scripts/init.py index 020a660797852353077ff6c36a8f10834c1dd05a..6df88ea013347837d43e8b155141325da09f6fb2 100644 --- a/scripts/init.py +++ b/scripts/init.py @@ -36,7 +36,6 @@ def _InitPanels(app): panels.AddWidgetToPool('ost.gui.RemoteLoader', -1) panels.AddWidgetToPool('ost.gui.SceneWin', 1) panels.AddWidgetToPool('ost.gui.SequenceViewer', 1) - panels.AddWidgetToPool('ost.gui.SequenceViewerV2', 1) if not panels.Restore("ui/perspective/panels"): panels.AddWidget(gui.PanelPosition.LEFT_PANEL, app.scene_win) panels.AddWidgetByName(gui.PanelPosition.LEFT_PANEL,