diff --git a/.gitignore b/.gitignore index 999865f42d6427ffadb3da685ee7fee4c340848d..68136f8be070c507f06fc835f6b646660bdffdb7 100644 --- a/.gitignore +++ b/.gitignore @@ -57,6 +57,8 @@ Debug *.cxx_parameters /deployment/win/create_archive.bat /install_manifest.txt +/modules/gui/src/module_config.hh +/modules/gui/src/dngr.qrc.depends *_out.csv *_out.tab *_out.pickle diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 4151f7269f101d4cc37d7d97d5bafff65945cc65..af007259420189de595538d71a69c4e3aea0bde0 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,3 +1,8 @@ +Changes in Release 1.2.2 + + * Fixed loop indentation in the PDBize function for bio units, leading to + exponential running time/ memory consumption. This problem only affected a + fraction of PDB entries. Changes in Release 1.2.1 -------------------------------------------------------------------------------- diff --git a/CMakeLists.txt b/CMakeLists.txt index c8651ec834cfe3a60a435c603e234a1c6dcaf615..346da8a262f31c8093787c5a933e9aca18c63aa5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -152,7 +152,7 @@ add_definitions(-DEIGEN2_SUPPORT) if (COMPOUND_LIB) set(_COMP_LIB "${COMPOUND_LIB}") if (NOT IS_ABSOLUTE "${COMPOUND_LIB}") - set(COMPOUND_LIB "${CMAKE_CURRENT_SOURCE_DIR}/${COMPOUND_LIB}") + set(COMPOUND_LIB "${CMAKE_CURRENT_BINARY_DIR}/${COMPOUND_LIB}") endif() else() set(_COMP_LIB "NONE") diff --git a/cmake_support/OST.cmake b/cmake_support/OST.cmake index 902619dd345b360595f97de19053c7393e09dcb8..e6dfb2ae0d4fb748a455f89e0ed51524acab4ba9 100644 --- a/cmake_support/OST.cmake +++ b/cmake_support/OST.cmake @@ -1,10 +1,48 @@ #------------------------------------------------------------------------------- -# Author: Marco Biasini, Juergen Haas +# Authors: Marco Biasini, Juergen Haas, Andreas Schenk # # This file contains a bunch of useful macros to facilitate the build-system # configuration for the modules. #------------------------------------------------------------------------------- +#------------------------------------------------------------------------------- +# map macro +# +# this function emulates a map/dict data type +#------------------------------------------------------------------------------- + +function(map COMMAND MAPNAME) + set (_KEYS ${MAPNAME}_MAP_KEYS ) + set (_VALUES ${MAPNAME}_MAP_VALUES) + if(${COMMAND} STREQUAL SET) + list(REMOVE_AT ARGN 0) + list(FIND ${_KEYS} ${ARGV2} _MAP_INDEX) + if(_MAP_INDEX EQUAL -1) + list(APPEND ${_KEYS} ${ARGV2}) + set(${_KEYS} ${${_KEYS}} PARENT_SCOPE) + set(${_VALUES}_${ARGV2} ${ARGN} PARENT_SCOPE) + else() + set(${_VALUES}_${ARGV2} ${ARGN} PARENT_SCOPE) + endif() + elseif(${COMMAND} STREQUAL GET) + list(FIND ${_KEYS} ${ARGV2} _MAP_INDEX) + if(_MAP_INDEX EQUAL -1) + MESSAGE(FATAL_ERROR "Unknown key: " ${ARGV2}) + endif() + set(${ARGV3} ${${_VALUES}_${ARGV2}} PARENT_SCOPE) + elseif(${COMMAND} STREQUAL KEYS) + set(${ARGV2} ${${_KEYS}} PARENT_SCOPE) + elseif(${COMMAND} STREQUAL CREATE) + set(${_KEYS} "" PARENT_SCOPE) + elseif(${COMMAND} STREQUAL LENGTH) + list(LENGTH ${_KEYS} _L) + set(${ARGV2} ${_L} PARENT_SCOPE) + else() + MESSAGE(FATAL_ERROR "Unknown map command:" ${COMMAND}) + endif() +endfunction() + + #------------------------------------------------------------------------------- # check_architecture # @@ -89,32 +127,36 @@ macro(copy_if_different FROM_DIR TO_DIR FILES TARGETS TARGET) endforeach() endmacro() + #------------------------------------------------------------------------------- -# stage_headers -#------------------------------------------------------------------------------- -macro(stage_headers HEADERS HEADER_INSTALL_DIR TARGET SUB) - set(FROM_DIR "./") - set(_HDR_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${SUB}") - foreach(_HDR ${HEADERS}) - list(APPEND _ABS_HEADER_NAMES ${_HDR_SOURCE_DIR}/${_HDR}) +# parse_file_list +# +# this macro splits a list of files with IN_DIR statements and fills them into a map +# where the key is the directory name +#------------------------------------------------------------------------------- +macro(parse_file_list FILELIST FILEMAP) + set(_EXPECT_IN_DIR FALSE) + map(CREATE ${FILEMAP}) + set(_CURRENT_LIST) + foreach(_ITEM ${FILELIST}) + if (_ITEM STREQUAL "IN_DIR") + set(_EXPECT_IN_DIR TRUE) + else() + if (_EXPECT_IN_DIR) + set(_EXPECT_IN_DIR FALSE) + map(SET ${FILEMAP} ${_ITEM} ${_CURRENT_LIST}) + set(_CURRENT_LIST) + else() + list(APPEND _CURRENT_LIST "${_ITEM}") + endif() + endif() endforeach() - # introduce a helper target to make sure the headers are staged before - # building the library - string(REPLACE "/" "_" _SUB_NO_SLASH "${SUB}") - string(REPLACE "${PREFIX}_" "" _TARGET "${TARGET}") - set(_TARGET_NAME ${_TARGET}_${_SUB_NO_SLASH}_headers) - set(_SUB ${SUB}) - if (NOT _SUB) - set(_TARGET_NAME ${_TARGET}_headers) - endif() - add_custom_target("${_TARGET_NAME}" COMMENT "") - set(HEADER_DIR "${HEADER_STAGE_PATH}/${HEADER_INSTALL_DIR}") - copy_if_different("" "${HEADER_DIR}" - "${_ABS_HEADER_NAMES}" "" - "${_TARGET_NAME}") - add_dependencies(${TARGET} ${_TARGET_NAME}) + if(_CURRENT_LIST) + map(SET ${FILEMAP} "." ${_CURRENT_LIST}) + endif() endmacro() + #------------------------------------------------------------------------------- # Synopsis: # module(NAME name SOURCES source1 source2 HEADERS header1 header2 @@ -142,17 +184,9 @@ macro(module) if (_ARG_HEADER_OUTPUT_DIR) set(_HEADER_OUTPUT_DIR ${_ARG_HEADER_OUTPUT_DIR}) else() - if (_ARG_PREFIX) - set(_HEADER_OUTPUT_DIR "${_ARG_PREFIX}/${_ARG_NAME}") - else() - set(_HEADER_OUTPUT_DIR "${_ARG_NAME}") - endif() - endif() - if (_ARG_PREFIX) - set(_LIB_NAME ${_ARG_PREFIX}_${_ARG_NAME}) - else() - set(_LIB_NAME ${_ARG_NAME}) + set(_HEADER_OUTPUT_DIR "${_ARG_PREFIX}/${_ARG_NAME}") endif() + set(_LIB_NAME ${_ARG_PREFIX}_${_ARG_NAME}) string(TOUPPER ${_LIB_NAME} _UPPER_LIB_NAME) #----------------------------------------------------------------------------- # create library @@ -161,17 +195,11 @@ macro(module) file(MAKE_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}) file(MAKE_DIRECTORY ${LIBEXEC_STAGE_PATH}) file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/tests") - if (NOT TARGET make_stage_lib_dir) - add_custom_target(make_stage_lib_dir COMMAND ${CMAKE_COMMAND} -E make_directory ${LIB_STAGE_PATH}) - endif() - if (NOT TARGET make_executable_output_dir) - add_custom_target(make_executable_output_dir COMMAND ${CMAKE_COMMAND} -E make_directory ${EXECUTABLE_OUTPUT_PATH}) - endif() - if (NOT TARGET make_libexec_dir) - add_custom_target(make_libexec_dir COMMAND ${CMAKE_COMMAND} -E make_directory ${LIBEXEC_STAGE_PATH}) - endif() - if (NOT TARGET make_tests_dir) - add_custom_target(make_tests_dir COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/tests") + if (NOT TARGET create_stage) + add_custom_target(create_stage COMMAND ${CMAKE_COMMAND} -E make_directory ${LIB_STAGE_PATH} + COMMAND ${CMAKE_COMMAND} -E make_directory ${EXECUTABLE_OUTPUT_PATH} + COMMAND ${CMAKE_COMMAND} -E make_directory ${LIBEXEC_STAGE_PATH} + COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/tests") endif() if (WIN32) set(_ABS_FILE_PATTERN "^[A-Z]:/") @@ -199,10 +227,7 @@ macro(module) EchoString ${_ARG_NAME} MODULE_DEPS "${_ARG_DEPENDS_ON}") get_target_property(_DEFS ${_LIB_NAME} COMPILE_DEFINITIONS) - add_dependencies(${_LIB_NAME} make_stage_lib_dir) - add_dependencies(${_LIB_NAME} make_executable_output_dir) - add_dependencies(${_LIB_NAME} make_libexec_dir) - add_dependencies(${_LIB_NAME} make_tests_dir) + add_dependencies(${_LIB_NAME} create_stage) set_target_properties(${_LIB_NAME} PROPERTIES COMPILE_DEFINITIONS OST_MODULE_${_UPPER_LIB_NAME}) set_target_properties(${_LIB_NAME} PROPERTIES @@ -236,7 +261,6 @@ macro(module) if (ENABLE_STATIC) target_link_libraries(${_LIB_NAME} ${STATIC_LIBRARIES}) endif() - else() add_custom_target("${_LIB_NAME}" ALL) set_target_properties("${_LIB_NAME}" PROPERTIES HEADER_ONLY 1 @@ -246,47 +270,33 @@ macro(module) # stage headers #----------------------------------------------------------------------------- if (_ARG_HEADERS) - set(_HEADERS) - set(_EXPECT_IN_DIR FALSE) - foreach(_HEADER ${_ARG_HEADERS}) - if (_HEADER STREQUAL "IN_DIR") - set(_EXPECT_IN_DIR TRUE) - else() - if (_EXPECT_IN_DIR) - set(_EXPECT_IN_DIR FALSE) - set(_DIR ${_HEADER}) - set(_ABS_HEADER_NAMES) - set(_HDR_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${_DIR}") - foreach(_HDR ${_HEADERS}) - list(APPEND _ABS_HEADER_NAMES "${_HDR_SOURCE_DIR}/${_HDR}") - endforeach() - install(FILES ${_ABS_HEADER_NAMES} DESTINATION - "include/${_HEADER_OUTPUT_DIR}/${_DIR}") - set(_HDR_STAGE_DIR "${_HEADER_OUTPUT_DIR}/${_DIR}") - stage_headers("${_HEADERS}" "${_HDR_STAGE_DIR}" - "${_LIB_NAME}" "${_DIR}") - set(_HEADERS) - else() - list(APPEND _HEADERS "${_HEADER}") - endif() - endif() - endforeach() - list(LENGTH _HEADERS _HEADER_LIST_LENGTH) - if (_HEADER_LIST_LENGTH GREATER 0) - set(_ABS_HEADER_NAMES) - set(_HDR_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") - foreach(_HDR ${_HEADERS}) - list(APPEND _ABS_HEADER_NAMES "${_HDR_SOURCE_DIR}/${_HDR}") - endforeach() - install(FILES ${_ABS_HEADER_NAMES} DESTINATION - "include/${_HEADER_OUTPUT_DIR}") - set(_HDR_STAGE_DIR "${_HEADER_OUTPUT_DIR}") - stage_headers("${_HEADERS}" "${_HDR_STAGE_DIR}" - "${_LIB_NAME}" "") - endif() + stage_and_install_headers("${_ARG_HEADERS}" "${_HEADER_OUTPUT_DIR}" "${_LIB_NAME}") endif() endmacro() +#------------------------------------------------------------------------------- +# macro stage_and_install_headers +#------------------------------------------------------------------------------- +macro(stage_and_install_headers HEADERLIST HEADER_OUTPUT_DIR TARGET) + add_custom_target("${TARGET}_headers" COMMENT "") + add_dependencies("${TARGET}" "${TARGET}_headers") + add_dependencies("${TARGET}_headers" create_stage) + parse_file_list("${HEADERLIST}" _HEADER_MAP) + map(KEYS _HEADER_MAP _HEADER_MAP_KEYS) + foreach(_DIR ${_HEADER_MAP_KEYS}) + map(GET _HEADER_MAP ${_DIR} _HEADERS) + set(_HDR_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${_DIR}") + set(_ABS_HEADER_NAMES) + foreach(_HDR ${_HEADERS}) + list(APPEND _ABS_HEADER_NAMES ${_HDR_SOURCE_DIR}/${_HDR}) + endforeach() + set(_HDR_STAGE_DIR "${HEADER_OUTPUT_DIR}/${_DIR}") + set(_FULL_HEADER_DIR "${HEADER_STAGE_PATH}/${_HDR_STAGE_DIR}") + copy_if_different("" "${_FULL_HEADER_DIR}" "${_ABS_HEADER_NAMES}" "" "${TARGET}_headers") + install(FILES ${_ABS_HEADER_NAMES} DESTINATION "include/${_HDR_STAGE_DIR}") + endforeach() +endmacro() + #------------------------------------------------------------------------------- # Synopsis @@ -422,13 +432,14 @@ endmacro() #------------------------------------------------------------------------------- # Synopsis: -# ui_to_python(module out_files [input_file1 ...]) +# ui_to_python(libname stagedir[input_file1 ...]) # Description: # Calls pyuic on every input file. The resulting python files are stored in # the variable with name out_files. #------------------------------------------------------------------------------- -macro(ui_to_python module out_files) +macro(ui_to_python LIBNAME STAGEDIR) set(_input_files ${ARGN}) + add_custom_target("${LIBNAME}_ui" ALL) find_program(_PYUIC_EXECUTABLE NAMES pyuic4-${PYTHON_VERSION} pyuic4 pyuic PATHS ENV PATH @@ -436,17 +447,19 @@ macro(ui_to_python module out_files) if(NOT _PYUIC_EXECUTABLE) message(FATAL_ERROR "Could not find pyuic command in " ${QT_BINARY_DIR} " for python version " ${PYTHON_VERSION}) endif(NOT _PYUIC_EXECUTABLE) - + set(out_files) foreach(input_file ${_input_files}) get_filename_component(_out_file ${input_file} NAME_WE) get_filename_component(_in_file ${input_file} ABSOLUTE) - set(_out_file ${CMAKE_CURRENT_SOURCE_DIR}/${_out_file}_ui.py) - add_custom_command(TARGET ${module} - COMMAND ${_PYUIC_EXECUTABLE} -o ${_out_file} ${_in_file} + set(_out_file ${_out_file}_ui.py) + set(_abs_out_file ${STAGEDIR}/${_out_file}) + add_custom_command(TARGET ${LIBNAME}_ui + COMMAND ${_PYUIC_EXECUTABLE} -o ${_abs_out_file} ${_in_file} VERBATIM DEPENDS ${input_file} ) - list(APPEND ${out_files} ${_out_file}) + list(APPEND ${out_files} ${_abs_out_file}) endforeach() + compile_py_files(_${LIBNAME} ${STAGEDIR} ${out_files}) endmacro() #------------------------------------------------------------------------------- @@ -502,6 +515,7 @@ macro(pymod) set(_LIB_NAME ${_ARG_PREFIX}_${_ARG_NAME}) set(PYMOD_STAGE_DIR "${LIB_STAGE_PATH}/${PYMOD_DIR}") file(MAKE_DIRECTORY ${PYMOD_STAGE_DIR}) + include_directories(${PYTHON_INCLUDE_PATH}) #----------------------------------------------------------------------------- # compile and link C++ wrappers #----------------------------------------------------------------------------- @@ -556,56 +570,35 @@ macro(pymod) else() add_custom_target("_${_LIB_NAME}" ALL) endif() - set(_PY_FILES) + #----------------------------------------------------------------------------- + # build ui files + #----------------------------------------------------------------------------- if (_ARG_UI) - add_custom_target("${_LIB_NAME}_ui") - ui_to_python("${_LIB_NAME}_ui" _PY_FILES ${_ARG_UI}) + ui_to_python(${_LIB_NAME} ${PYMOD_STAGE_DIR} ${_ARG_UI}) endif() - if (_ARG_PY OR _PY_FILES) - set(_EXPECT_IN_DIR FALSE) - foreach(_PY_FILE ${_ARG_PY}) - if (_PY_FILE STREQUAL "IN_DIR") - set(_EXPECT_IN_DIR TRUE) - else() - if (_EXPECT_IN_DIR) - set(_EXPECT_IN_DIR FALSE) - set(_DIR ${_PY_FILE}) - set(_ABS_PY_FILES) - set(_PY_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${_DIR}") - foreach(_PY ${_PY_FILES}) - list(APPEND _ABS_PY_FILES "${_PY_SOURCE_DIR}/${_PY}") - endforeach() - install(FILES ${_ABS_PY_FILES} DESTINATION - "${LIB_DIR}/${PYMOD_DIR}/${_DIR}") - string(REPLACE "/" "_" _DIR_NO_SLASH "${_DIR}") - add_custom_target("${_ARG_NAME}_${_DIR_NO_SLASH}_pymod" ALL) - copy_if_different("./" "${PYMOD_STAGE_DIR}/${_DIR}" - "${_ABS_PY_FILES}" "TARGETS" - "${_ARG_NAME}_${_DIR_NO_SLASH}_pymod") - compile_py_files(_${_LIB_NAME} ${PYMOD_STAGE_DIR}/${_DIR} ${_ABS_PY_FILES}) - set(_PY_FILES) - else() - list(APPEND _PY_FILES "${_PY_FILE}") - endif() - endif() - endforeach() - if (_PY_FILES) - add_custom_target("${_LIB_NAME}_pymod" ALL) - if (_ARG_UI) - add_dependencies("${_LIB_NAME}_pymod" "${_LIB_NAME}_ui"}) - endif() + #----------------------------------------------------------------------------- + # compile python files + #----------------------------------------------------------------------------- + if (_ARG_PY) + parse_file_list("${_ARG_PY}" _PYFILE_MAP) + map(KEYS _PYFILE_MAP _PYFILE_MAP_KEYS) + foreach(_DIR ${_PYFILE_MAP_KEYS}) + map(GET _PYFILE_MAP ${_DIR} _PY_FILES) set(_ABS_PY_FILES) - set(_PY_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") + set(_PY_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${_DIR}") foreach(_PY ${_PY_FILES}) list(APPEND _ABS_PY_FILES "${_PY_SOURCE_DIR}/${_PY}") endforeach() - copy_if_different("./" "${PYMOD_STAGE_DIR}" "${_ABS_PY_FILES}" "TARGETS" - "${_LIB_NAME}_pymod") - add_dependencies("_${_LIB_NAME}" "${_LIB_NAME}_pymod") - compile_py_files(_${_LIB_NAME} ${PYMOD_STAGE_DIR} ${_PY_FILES}) - include_directories(${PYTHON_INCLUDE_PATH}) - install(FILES ${_PY_FILES} DESTINATION "${LIB_DIR}/${PYMOD_DIR}") - endif() + install(FILES ${_ABS_PY_FILES} DESTINATION "${LIB_DIR}/${PYMOD_DIR}/${_DIR}") + string(REPLACE "/" "_" _DIR_NO_SLASH "${_DIR}") + set(_PYMOD_TARGET "${_LIB_NAME}_${_DIR_NO_SLASH}_pymod") + string(REPLACE "_." "" _PYMOD_TARGET "${_PYMOD_TARGET}") + add_custom_target(${_PYMOD_TARGET} ALL) + copy_if_different("./" "${PYMOD_STAGE_DIR}/${_DIR}" + "${_ABS_PY_FILES}" "TARGETS" + "${_PYMOD_TARGET}") + compile_py_files(_${_LIB_NAME} ${PYMOD_STAGE_DIR}/${_DIR} ${_ABS_PY_FILES}) + endforeach() endif() get_target_property(_MOD_DEPS "${_PARENT_NAME}" MODULE_DEPS) if(_MOD_DEPS) diff --git a/examples/gfx/solid.py b/examples/gfx/solid.py new file mode 100644 index 0000000000000000000000000000000000000000..1840068d410410c1b0394ae2becab4ba2dfe6c99 --- /dev/null +++ b/examples/gfx/solid.py @@ -0,0 +1,18 @@ +s=io.LoadSurface("../demos/data/sh2","msms") +scene.Add(gfx.Surface("s",s)) + +# alternative shading mode +scene.SetShadingMode("hf") + +# add outlines to surface +scene["s"].SetOutline(True) +scene["s"].SetOutlineMode(3) + +# turn on solid rendering +scene["s"].solid=True +scene["s"].solid_color=gfx.RGB(0.8,0.8,0.7) + +scene.AutoAutoslab(False) +scene.far=170 +scene.near=100 +scene.fog=False diff --git a/modules/base/pymod/settings.py b/modules/base/pymod/settings.py index 56bf46b4aeedf36cfcd471390cf361860608682e..34afdc0b2c9bd0db42619ab898b83a544dc48d7f 100644 --- a/modules/base/pymod/settings.py +++ b/modules/base/pymod/settings.py @@ -1,6 +1,18 @@ import os, platform import __main__ +def GetPlatform(): + """ + Returns platform.system(). If the system call is interrupted, it is repeated. + This function is a workaround for the buggy system call handling in Python. + """ + system=None + while not system: + try: + system=platform.system() + except IOError: + pass + return system def GetValue(val_key,val_default=None,prefix='OST'): """ @@ -89,7 +101,7 @@ def Locate(file_name, explicit_file_name=None, search_paths=[], if search_system_paths: paths=os.getenv('PATH') - if platform.system() == "Windows": + if GetPlatform() == "Windows": searched+=paths.split(';') else: searched+=paths.split(':') diff --git a/modules/base/pymod/table.py b/modules/base/pymod/table.py index 8af2ab6cc20f088401c9e80038d8bc98e31f8561..37c45feb9f9c6589dd4b9eba45bc70852322c796 100644 --- a/modules/base/pymod/table.py +++ b/modules/base/pymod/table.py @@ -90,6 +90,9 @@ class BinaryColExpr: def __mul__(self, rhs): return BinaryColExpr(operator.mul, self, rhs) + def __div__(self, rhs): + return BinaryColExpr(operator.div, self, rhs) + class TableCol: def __init__(self, table, col): self._table=table @@ -119,6 +122,7 @@ class TableCol: def __mul__(self, rhs): return BinaryColExpr(operator.mul, self, rhs) + def __div__(self, rhs): return BinaryColExpr(operator.div, self, rhs) @@ -271,6 +275,19 @@ class Table(object): ''' return self.name + def RenameCol(self, old_name, new_name): + """ + Rename column *old_name* to *new_name*. + + :param old_name: Name of the old column + :param new_name: Name of the new column + :raises: :exc:`ValueError` when *old_name* is not a valid column + """ + if old_name==new_name: + return + self.AddCol(new_name, self.col_types[self.GetColIndex(old_name)], + self[old_name]) + self.RemoveCol(old_name) def _Coerce(self, value, ty): ''' Try to convert values (e.g. from :class:`str` type) to the specified type @@ -314,6 +331,22 @@ class Table(object): ''' return self.col_names + def SearchColNames(self, regex): + ''' + Returns a list of column names matching the regex + + :param regex: regex pattern + :type regex: :class:`str` + + :returns: :class:`list` of column names (:class:`str`) + ''' + matching_names = [] + for name in self.col_names: + matches = re.search(regex, name) + if matches: + matching_names.append(name) + return matching_names + def HasCol(self, col): ''' Checks if the column with a given name is present in the table. @@ -395,6 +428,31 @@ class Table(object): def __str__(self): return self.ToString() + def Stats(self, col): + idx = self.GetColIndex(col) + text =''' +Statistics for column %(col)s + + Number of Rows : %(num)d + Number of Rows Not None: %(num_non_null)d + Mean : %(mean)f + Median : %(median)f + Standard Deviation : %(stddev)f + Min : %(min)f + Max : %(max)f +''' + data = { + 'col' : col, + 'num' : len(self.rows), + 'num_non_null' : self.Count(col), + 'median' : self.Median(col), + 'mean' : self.Mean(col), + 'stddev' : self.StdDev(col), + 'min' : self.Min(col), + 'max' : self.Max(col), + } + return text % data + def _AddRowsFromDict(self, d, overwrite=None): ''' Add one or more rows from a :class:`dictionary <dict>`. @@ -453,6 +511,27 @@ class Table(object): if not overwrite or not added: self.rows.append(new_row) + def PairedTTest(self, col_a, col_b): + """ + Two-sided test for the null-hypothesis that two related samples + have the same average (expected values) + + :param col_a: First column + :param col_b: Second column + + :returns: P-value between 0 and 1 that the two columns have the + same average. The smaller the value, the less related the two + columns are. + """ + from scipy.stats import ttest_rel + xs = [] + ys = [] + for x, y in self.Zip(col_a, col_b): + if x!=None and y!=None: + xs.append(x) + ys.append(y) + result = ttest_rel(xs, ys) + return result[1] def AddRow(self, data, overwrite=None): """ @@ -629,6 +708,10 @@ class Table(object): As a special case, if there are no previous rows, and data is not None, rows are added for every item in data. """ + + if col_name in self.col_names: + raise ValueError('Column with name %s already exists'%col_name) + col_type = self._ParseColTypes(col_type, exp_num=1)[0] self.col_names.append(col_name) self.col_types.append(col_type) @@ -638,10 +721,15 @@ class Table(object): for row in self.rows: row.append(data) else: + if hasattr(data, '__len__') and len(data)!=len(self.rows): + self.col_names.pop() + self.col_types.pop() + raise ValueError('Length of data (%i) must correspond to number of '%len(data) +\ + 'existing rows (%i)'%len(self.rows)) for row, d in zip(self.rows, data): row.append(d) - elif data!=None: + elif data!=None and len(self.col_names)==1: if IsScalar(data): self.AddRow({col_name : data}) else: @@ -668,7 +756,7 @@ class Table(object): args are unary callables returning true if the row should be included in the result and false if not. """ - filt_tab=Table(self.col_names, self.col_types) + filt_tab=Table(list(self.col_names), list(self.col_types)) for row in self.rows: matches=True for func in args: @@ -897,8 +985,9 @@ class Table(object): def Plot(self, x, y=None, z=None, style='.', x_title=None, y_title=None, z_title=None, x_range=None, y_range=None, z_range=None, color=None, plot_if=None, legend=None, - num_z_levels=10, diag_line=False, labels=None, max_num_labels=None, - title=None, clear=True, save=False, **kwargs): + num_z_levels=10, z_contour=True, z_interpol='nn', diag_line=False, + labels=None, max_num_labels=None, title=None, clear=True, save=False, + **kwargs): """ Function to plot values from your table in 1, 2 or 3 dimensions using `Matplotlib <http://matplotlib.sourceforge.net>`__ @@ -971,6 +1060,13 @@ class Table(object): :param save: filename for saving plot :type save: :class:`str` + :param z_contour: draw contour lines + :type z_contour: :class:`bool` + + :param z_interpol: interpolation method for 3-dimensional plot (one of 'nn', + 'linear') + :type z_interpol: :class:`str` + :param \*\*kwargs: additional arguments passed to matplotlib :returns: the ``matplotlib.pyplot`` module @@ -1009,12 +1105,12 @@ class Table(object): if clear: plt.figure(figsize=[8, 6]) - if x_title: + if x_title!=None: nice_x=x_title else: nice_x=MakeTitle(x) - if y_title: + if y_title!=None: nice_y=y_title else: if y: @@ -1022,7 +1118,7 @@ class Table(object): else: nice_y=None - if z_title: + if z_title!=None: nice_z = z_title else: if z: @@ -1063,11 +1159,13 @@ class Table(object): levels.append(l) l += z_spacing - xi = np.linspace(min(xs)-0.1,max(xs)+0.1,len(xs)*10) - yi = np.linspace(min(ys)-0.1,max(ys)+0.1,len(ys)*10) - zi = mlab.griddata(xs, ys, zs, xi, yi) + xi = np.linspace(min(xs),max(xs),len(xs)*10) + yi = np.linspace(min(ys),max(ys),len(ys)*10) + zi = mlab.griddata(xs, ys, zs, xi, yi, interp=z_interpol) - plt.contour(xi,yi,zi,levels,linewidths=0.5,colors='k') + if z_contour: + plt.contour(xi,yi,zi,levels,linewidths=0.5,colors='k') + plt.contourf(xi,yi,zi,levels,cmap=plt.cm.jet) plt.colorbar(ticks=levels) @@ -1269,7 +1367,208 @@ class Table(object): max_val = self.rows[i][idx] max_idx = i return max_val, max_idx + + def PlotBar(self, col, xlabels=None, ylabel=None, title=None, + color=None, yerr=None, width=0.8, bottom=0, + legend=True, save=False): + + try: + import numpy as np + import matplotlib.pyplot as plt + except: + raise ImportError('PlotBar relies on numpy and matplotlib, but I could not import it!') + + if len(col)>7: + raise ValueError('More than seven bars at one position looks rather meaningless...') + + standard_colors=['b','g','y','c','m','r','k'] + data=[] + + if not isinstance(col,list): + col=[col] + if not isinstance(yerr,list): + yerr=[yerr]*len(self.rows) + + if not color: + color=standard_colors[:len(col)] + + for c in col: + cid=self.GetColIndex(c) + temp=list() + for r in self.rows: + temp.append(r[cid]) + data.append(temp) + + if len(yerr)!=len(data[0]): + raise RuntimeError('Number of elements in yerr must be consistent with number of elements in each column!') + + ind=np.arange(len(data[0])) + single_bar_width=float(width)/len(data) + + fig=plt.figure() + + ax=fig.add_subplot(111) + + legend_data=[] + + for i in range(len(data)): + legend_data.append(ax.bar(ind+i*single_bar_width,data[i],single_bar_width,color=color[i],yerr=yerr[i])[0]) + + if title!=None: + nice_title=x_title + else: + nice_title="coolest barplot on earth" + ax.set_title(nice_title, size='x-large', fontweight='bold') + + if ylabel!=None: + nice_y=ylabel + else: + nice_y="score" + ax.set_ylabel(nice_y) + + if xlabels: + if len(data[0])!=len(xlabels): + raise ValueError('Number of xlabels is not consistent with number of rows!') + else: + xlabels=list() + for i in range(1,len(data[0])+1): + xlabels.append('Row '+str(i)) + + ax.set_xticks(ind+width*0.5) + ax.set_xticklabels(xlabels) + + if legend: + ax.legend(legend_data, col) + + if save: + plt.savefig(save) + + return plt + + def PlotHexbin(self, x, y, title=None, x_title=None, y_title=None, x_range=None, y_range=None, binning='log', + colormap='jet', show_scalebar=False, scalebar_label=None, clear=True, save=False, show=False): + + """ + Create a heatplot of the data in col x vs the data in col y using matplotlib + + :param x: column name with x data + :type x: :class:`str` + + :param y: column name with y data + :type y: :class:`str` + + :param title: title of the plot, will be generated automatically if set to None + :type title: :class:`str` + + :param x_title: label of x-axis, will be generated automatically if set to None + :type title: :class:`str` + + :param y_title: label of y-axis, will be generated automatically if set to None + :type title: :class:`str` + + :param x_range: start and end value for first dimension (e.g. [start_x, end_x]) + :type x_range: :class:`list` of length two + + :param y_range: start and end value for second dimension (e.g. [start_y, end_y]) + :type y_range: :class:`list` of length two + + :param binning: type of binning. If set to None, the value of a hexbin will + correspond to the number of datapoints falling into it. If + set to 'log', the value will be the log with base 10 of the above + value (log(i+1)). If an integer is provided, the number of a + hexbin is equal the number of datapoints falling into it divided + by the integer. If a list of values is provided, these values + will be the lower bounds of the bins. + + :param colormap: colormap, that will be used. Value can be every colormap defined + in matplotlib or an own defined colormap. You can either pass a + string with the name of the matplotlib colormap or a colormap + object. + + :param show_scalebar: If set to True, a scalebar according to the chosen colormap is shown + :type show_scalebar: :class:`bool` + + :param scalebar_label: Label of the scalebar + :type scalebar_label: :class:`str` + + :param clear: clear old data from plot + :type clear: :class:`bool` + + :param save: filename for saving plot + :type save: :class:`str` + + :param show: directly show plot + :type show: :class:`bool` + + """ + + try: + import matplotlib.pyplot as plt + import matplotlib.cm as cm + except: + raise ImportError('PlotHexbin relies on matplotlib, but I could not import it') + + idx=self.GetColIndex(x) + idy=self.GetColIndex(y) + xdata=[] + ydata=[] + + for r in self.rows: + if r[idx]!=None and r[idy]!=None: + xdata.append(r[idx]) + ydata.append(r[idy]) + + if clear: + plt.clf() + + if x_title!=None: + nice_x=x_title + else: + nice_x=MakeTitle(x) + + if y_title!=None: + nice_y=y_title + else: + nice_y=MakeTitle(y) + + if title==None: + title = '%s vs. %s' % (nice_x, nice_y) + if IsStringLike(colormap): + colormap=getattr(cm, colormap) + + if x_range and (IsScalar(x_range) or len(x_range)!=2): + raise ValueError('parameter x_range must contain exactly two elements') + if y_range and (IsScalar(y_range) or len(y_range)!=2): + raise ValueError('parameter y_range must contain exactly two elements') + if x_range: + plt.xlim((x_range[0], x_range[1])) + if y_range: + plt.ylim(y_range[0], y_range[1]) + extent = None + if x_range and y_range: + extent = [x_range[0], x_range[1], y_range[0], y_range[1]] + plt.hexbin(xdata, ydata, bins=binning, cmap=colormap, extent=extent) + + plt.title(title, size='x-large', fontweight='bold', + verticalalignment='bottom') + + plt.xlabel(nice_x) + plt.ylabel(nice_y) + + if show_scalebar: + cb=plt.colorbar() + if scalebar_label: + cb.set_label(scalebar_label) + + if save: + plt.savefig(save) + + if show: + plt.show() + + return plt + def MaxRow(self, col): """ Returns the row containing the cell with the maximal value in col. If @@ -1278,9 +1577,12 @@ class Table(object): :param col: column name :type col: :class:`str` + + :returns: row with maximal col value or None if the table is empty """ val, idx = self._Max(col) - return self.rows[idx] + if idx!=None: + return self.rows[idx] def Max(self, col): """ @@ -1342,9 +1644,12 @@ class Table(object): :param col: column name :type col: :class:`str` + + :returns: row with minimal col value or None if the table is empty """ val, idx = self._Min(col) - return self.rows[idx] + if idx!=None: + return self.rows[idx] def MinIdx(self, col): """ @@ -1480,6 +1785,45 @@ class Table(object): self.AddCol(mean_col_name, 'f', mean_rows) + def Percentiles(self, col, nths): + """ + returns the percentiles of column *col* given in *nths*. + + The percentils are calculated as + + .. code-block:: python + + values[min(len(values), int(round(len(values)*p/100+0.5)-1))] + + where values are the sorted values of *col* not equal to none + :param: nths: list of percentiles to be calculated. Each percentil is a number + between 0 and 100. + + :raises: :class:`TypeError` if column type is ``string`` + :returns: List of percentils in the same order as given in *nths* + """ + idx = self.GetColIndex(col) + col_type = self.col_types[idx] + if col_type!='int' and col_type!='float' and col_type!='bool': + raise TypeError("Median can only be used on numeric column types") + + for nth in nths: + if nth < 0 or nth > 100: + raise ValueError("percentiles must be between 0 and 100") + vals=[] + for v in self[col]: + if v!=None: + vals.append(v) + vals=sorted(vals) + if len(vals)==0: + return [None]*len(nths) + percentiles=[] + + for nth in nths: + p=vals[min(len(vals)-1, int(round(len(vals)*nth/100.0+0.5)-1))] + percentiles.append(p) + return percentiles + def Median(self, col): """ Returns the median of the given column. Cells with None are ignored. Returns @@ -1625,6 +1969,8 @@ class Table(object): ost ost-specific format (human readable) csv comma separated values (human readable) pickle pickled byte stream (binary) + html HTML table + context ConTeXt table ============= ======================================= :param stream_or_filename: filename or stream for writing output @@ -1642,6 +1988,10 @@ class Table(object): return self._SaveCSV(stream_or_filename, sep=sep) if format=='pickle': return self._SavePickle(stream_or_filename) + if format=='html': + return self._SaveHTML(stream_or_filename) + if format=='context': + return self._SaveContext(stream_or_filename) raise ValueError('unknown format "%s"' % format) def _SavePickle(self, stream): @@ -1649,6 +1999,79 @@ class Table(object): stream=open(stream, 'wb') cPickle.dump(self, stream, cPickle.HIGHEST_PROTOCOL) + def _SaveHTML(self, stream_or_filename): + def _escape(s): + return s.replace('&', '&').replace('>', '>').replace('<', '<') + + file_opened = False + if not hasattr(stream_or_filename, 'write'): + stream = open(stream_or_filename, 'w') + file_opened = True + else: + stream = stream_or_filename + stream.write('<table>') + stream.write('<tr>') + for col_name in self.col_names: + stream.write('<th>%s</th>' % _escape(col_name)) + stream.write('</tr>') + for row in self.rows: + stream.write('<tr>') + for i, col in enumerate(row): + val = '' + if col != None: + if self.col_types[i] == 'float': + val = '%.3f' % col + elif self.col_types[i] == 'int': + val = '%d' % col + elif self.col_types[i] == 'bool': + val = col and 'true' or 'false' + else: + val = str(col) + stream.write('<td>%s</td>' % _escape(val)) + stream.write('</tr>') + stream.write('</table>') + if file_opened: + stream.close() + def _SaveContext(self, stream_or_filename): + file_opened = False + if not hasattr(stream_or_filename, 'write'): + stream = open(stream_or_filename, 'w') + file_opened = True + else: + stream = stream_or_filename + stream.write('\\starttable[') + for col_type in self.col_types: + if col_type =='string': + stream.write('l|') + elif col_type=='int': + stream.write('r|') + elif col_type =='float': + stream.write('i3r|') + else: + stream.write('l|') + stream.write(']\n\\HL\n') + for col_name in self.col_names: + stream.write('\\NC \\bf %s' % col_name) + stream.write(' \\AR\\HL\n') + for row in self.rows: + for i, col in enumerate(row): + val = '---' + if col != None: + if self.col_types[i] == 'float': + val = '%.3f' % col + elif self.col_types[i] == 'int': + val = '%d' % col + elif self.col_types[i] == 'bool': + val = col and 'true' or 'false' + else: + val = str(col) + stream.write('\\NC %s' % val) + stream.write(' \\AR\n') + stream.write('\\HL\n') + stream.write('\\stoptable') + if file_opened: + stream.close() + def _SaveCSV(self, stream, sep): if not hasattr(stream, 'write'): stream=open(stream, 'wb') @@ -1712,7 +2135,7 @@ class Table(object): - def GaussianSmooth(self, col, std=1.0, na_value=0.0): + def GaussianSmooth(self, col, std=1.0, na_value=0.0, padding='reflect', c=0.0): ''' In place gaussian smooth of a column in the table with a given standard deviation. @@ -1727,13 +2150,22 @@ class Table(object): :param na_value: all na (None) values of the speciefied column are set to na_value before smoothing :type na_value: `scalar` + :param padding: allows to handle padding behaviour see scipy ndimage.gaussian_filter1d documentation for more information. standard is reflect + :type padding: :class:`str` + + :param c: constant value used for padding if padding mode is constant + :type c: `scalar` + + + :warning: The function depends on *scipy* ''' try: from scipy import ndimage + import numpy as np except ImportError: - LogError("Function needs scipy.ndimage, but I could no import it") + LogError("I need scipy.ndimage and numpy, but could not import it") raise idx = self.GetColIndex(col) @@ -1748,7 +2180,8 @@ class Table(object): else: vals.append(na_value) - smoothed_values_ndarray=ndimage.gaussian_filter1d(vals,std) + + smoothed_values_ndarray=ndimage.gaussian_filter1d(vals,std, mode=padding, cval=c) result=[] @@ -1905,6 +2338,8 @@ class Table(object): where a '-' values means smallest values first and therefore, the smaller the value, the better. + :warning: If either the value of *class_col* or *score_col* is *None*, the + data in this row is ignored. ''' ALLOWED_DIR = ['+','-'] @@ -1927,17 +2362,35 @@ class Table(object): x = [0] y = [0] enr = 0 - for i,row in enumerate(self.rows): + old_score_val = None + i = 0 + + for row in self.rows: class_val = row[class_idx] + score_val = row[score_idx] + if class_val==None or score_val==None: + continue if class_val!=None: + if old_score_val==None: + old_score_val = score_val + if score_val!=old_score_val: + x.append(i) + y.append(enr) + old_score_val = score_val + i+=1 if class_type=='bool': if class_val==True: enr += 1 else: if (class_dir=='-' and class_val<=class_cutoff) or (class_dir=='+' and class_val>=class_cutoff): enr += 1 - x.append(i+1) - y.append(enr) + x.append(i) + y.append(enr) + + # if no false positives or false negatives values are found return None + if x[-1]==0 or y[-1]==0: + return None + x = [float(v)/x[-1] for v in x] y = [float(v)/y[-1] for v in y] return x,y @@ -1956,10 +2409,12 @@ class Table(object): try: import numpy as np - enrx, enry = self.ComputeEnrichment(score_col, class_col, score_dir, + enr = self.ComputeEnrichment(score_col, class_col, score_dir, class_dir, class_cutoff) - return np.trapz(enry, enrx) + if enr==None: + return None + return np.trapz(enr[1], enr[0]) except ImportError: LogError("Function needs numpy, but I could not import it.") raise @@ -1990,6 +2445,9 @@ class Table(object): is of type bool) or evaluated to True (if column is of type int or float (depending on *class_dir* and *class_cutoff*))) the ROC is not defined and the function will return *None*. + + :warning: If either the value of *class_col* or *score_col* is *None*, the + data in this row is ignored. ''' ALLOWED_DIR = ['+','-'] @@ -2018,6 +2476,8 @@ class Table(object): for i,row in enumerate(self.rows): class_val = row[class_idx] score_val = row[score_idx] + if class_val==None or score_val==None: + continue if class_val!=None: if old_score_val==None: old_score_val = score_val @@ -2374,4 +2834,3 @@ def Merge(table1, table2, by, only_matching=False): new_tab.AddRow(row) return new_tab - diff --git a/modules/base/src/CMakeLists.txt b/modules/base/src/CMakeLists.txt index 6bc47461f8c012949e77afe150d9f996caca1730..e6691bc1de9af1dccafbaebad7b6b399b0fa81e4 100644 --- a/modules/base/src/CMakeLists.txt +++ b/modules/base/src/CMakeLists.txt @@ -8,6 +8,7 @@ string_ref.cc platform.cc message.cc test_utils/compare_files.cc +boost_filesystem_helper.cc ) set(OST_BASE_HEADERS @@ -30,6 +31,7 @@ string_ref.hh pod_vector.hh fixed_string.hh tri_matrix.hh +boost_filesystem_helper.hh ) set(OST_EXPORT_HELPERS diff --git a/modules/base/src/boost_filesystem_helper.cc b/modules/base/src/boost_filesystem_helper.cc new file mode 100644 index 0000000000000000000000000000000000000000..b235b0498dbb26fee19814e41692d254c2304f87 --- /dev/null +++ b/modules/base/src/boost_filesystem_helper.cc @@ -0,0 +1,22 @@ +//------------------------------------------------------------------------------ +// This file is part of the OpenStructure project <www.openstructure.org> +// +// Copyright (C) 2008-2011 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: Valerio Mariani +*/ + diff --git a/modules/base/src/boost_filesystem_helper.hh b/modules/base/src/boost_filesystem_helper.hh new file mode 100644 index 0000000000000000000000000000000000000000..5418253fd7553f7f715e8259d1f6f08615080ca1 --- /dev/null +++ b/modules/base/src/boost_filesystem_helper.hh @@ -0,0 +1,44 @@ +//------------------------------------------------------------------------------ +// This file is part of the OpenStructure project <www.openstructure.org> +// +// Copyright (C) 2008-2011 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: Valerio Mariani +*/ + +#ifndef OST_BOOST_FILESYSTEM_HELPER_HH +#define OST_BOOST_FILESYSTEM_HELPER_HH + +#include <boost/filesystem/path.hpp> + +namespace { + +inline +String BFPathToString(const boost::filesystem::path& path) +{ +#if BOOST_FILESYSTEM_VERSION==3 || BOOST_VERSION<103400 + return path.string(); +#else + return path.file_string(); +#endif +} + +} + + + +#endif // OST_BOOST_FILESYSTEM_HELPER diff --git a/modules/base/tests/test_string_ref.cc b/modules/base/tests/test_string_ref.cc index 8d69f0ce80ff297a7dd27149fdffad9548982cbe..05b9bd84416d083d7b9c178914550305fb922d95 100644 --- a/modules/base/tests/test_string_ref.cc +++ b/modules/base/tests/test_string_ref.cc @@ -30,7 +30,22 @@ using namespace ost; BOOST_AUTO_TEST_SUITE( base ); -BOOST_AUTO_TEST_CASE( test_string_ref) + +BOOST_AUTO_TEST_CASE(test_whitespace_split) +{ + std::string s=" 1 2 \r\n 3 4\t5 "; + StringRef sr(s.c_str(), s.size()); + std::vector<StringRef> srl=sr.split(); + BOOST_CHECK_EQUAL(srl.size(), static_cast<size_t>(5)); + BOOST_CHECK_EQUAL(srl[0], StringRef("1", 1)); + BOOST_CHECK_EQUAL(srl[1], StringRef("2", 1)); + BOOST_CHECK_EQUAL(srl[2], StringRef("3", 1)); + BOOST_CHECK_EQUAL(srl[3], StringRef("4", 1)); + BOOST_CHECK_EQUAL(srl[4], StringRef("5", 1)); +} + + +BOOST_AUTO_TEST_CASE(test_string_ref) { StringRef sr("12345", 5); BOOST_CHECK_EQUAL(sr.length(), size_t(5)); diff --git a/modules/base/tests/test_table.py b/modules/base/tests/test_table.py index 21fd58a679df759d4824c20c3a1104e3879bb652..cd11bd729623d9b5463f4cc8a67daf43a0f10cd6 100644 --- a/modules/base/tests/test_table.py +++ b/modules/base/tests/test_table.py @@ -163,6 +163,10 @@ class TestTable(unittest.TestCase): diff = ImageChops.difference(img1, img2) self.assertEqual(diff.getbbox(),None) + def testSearchColNames(self): + tab = self.CreateTestTable() + self.assertEquals(tab.SearchColNames('d$'), ['second', 'third']) + self.assertEquals(tab.SearchColNames('(first|third)'), ['first','third']) def testZip(self): tab=Table(['col1', 'col2', 'col3', 'col4'], 'sssi') @@ -192,7 +196,14 @@ class TestTable(unittest.TestCase): self.assertEquals(type(z[0][1]),int) self.assertEquals(type(z[1][1]),int) self.assertRaises(ValueError, tab.Zip, 'col5', 'col3') - + def testPercentiles(self): + tab = Table(['nums'], 'i') + self.assertEqual(tab.Percentiles('nums', [0,100]), [None, None]) + self.assertRaises(ValueError, tab.Percentiles, 'nums', [101]) + self.assertRaises(ValueError, tab.Percentiles, 'nums', [-1]) + for i in (35,15,50,40,20): + tab.AddRow([i]) + self.assertEqual(tab.Percentiles('nums', [0,30,40,100]), [15,20,35,50]) def testTableInitEmpty(self): ''' empty table @@ -304,6 +315,24 @@ class TestTable(unittest.TestCase): self.CompareColNames(tab, ['x']) self.CompareColTypes(tab, 'x', 'f') + def testTableFilterColNamesTypes(self): + """ + make sure the col_names and col_types are copied. + We don't want them to be referenced to the original table. + This leads to strange surprises. + """ + t = Table(['a', 'b'], 'ii') + t.AddRow([1,2]) + t.AddRow([2,3]) + t.AddRow([2,3]) + t.AddRow([3,3]) + t.AddRow([4,3]) + t.AddRow([5,3]) + filt = t.Filter(a=2) + filt.AddCol('c', 'i') + self.assertEqual(len(t.col_names), 2) + self.assertEqual(len(t.col_types), 2) + def testTableInitMultiColMultiValueNonEmpty(self): ''' table with two column and four rows: @@ -588,6 +617,15 @@ class TestTable(unittest.TestCase): 'foo': [True, None, True], 'bar': [1, 2, 3]}) + def testRaiseErrorOnWrongDataLengthAddCol(self): + tab = Table() + tab.AddCol('a','f',[4.2,4.2,4.2]) + self.assertRaises(ValueError, tab.AddCol, 'b', 'f', [4.2,4.2]) + + def testRaiseErrorColNameAlreadyExists(self): + tab = Table() + tab.AddCol('awesome','f') + self.assertRaises(ValueError, tab.AddCol, 'awesome', 'f') def testRaiseErrorOnWrongColumnTypes(self): # wrong columns types in init @@ -849,6 +887,19 @@ class TestTable(unittest.TestCase): # read from disc tab_loaded_fname = Table.Load('saveloadtable_withspaces_filename_out.tab') self.CompareDataFromDict(tab_loaded_fname, {'first': ['x','foo',None,'hello spaces'], 'second': [3,None,9,10], 'third': [None,2.2,3.3,10.1]}) + def testSaveTableHTML(self): + import StringIO + tab = self.CreateTestTable() + stream = StringIO.StringIO() + tab.Save(stream, format='html') + self.assertEqual(stream.getvalue(), '<table><tr><th>first</th><th>second</th><th>third</th></tr><tr><td>x</td><td>3</td><td></td></tr><tr><td>foo</td><td></td><td>2.200</td></tr><tr><td></td><td>9</td><td>3.300</td></tr></table>') + def testSaveTableContext(self): + import StringIO + tab = self.CreateTestTable() + stream = StringIO.StringIO() + tab.Save(stream, format='context') + self.assertEqual(stream.getvalue(), + '\\starttable[l|r|i3r|]\n\\HL\n\\NC \\bf first\\NC \\bf second\\NC \\bf third \\AR\\HL\n\\NC x\\NC 3\\NC --- \\AR\n\\NC foo\NC ---\NC 2.200 \\AR\n\\NC ---\\NC 9\\NC 3.300 \\AR\n\\HL\n\\stoptable') def testSaveLoadTableCSV(self): tab = self.CreateTestTable() @@ -1137,6 +1188,13 @@ class TestTable(unittest.TestCase): self.assertRaises(ValueError, tab.Plot, x='second', y='third', y_range=[1,2,3]) self.assertRaises(ValueError, tab.Plot, x='second', y='third', z_range='st') + def testHexbin(self): + if not HAS_MPL or not HAS_NUMPY: + return + tab = self.CreateTestTable() + self.assertRaises(ValueError, tab.PlotHexbin, x='second', y='third', x_range=1) + self.assertRaises(ValueError, tab.PlotHexbin, x='second', y='third', x_range=[1,2,3]) + def testPlotEnrichment(self): if not HAS_MPL or not HAS_PIL: return @@ -1154,6 +1212,24 @@ class TestTable(unittest.TestCase): #self.CompareImages(img1, img2) #pl.show() + def testCalcEnrichmentAUCwithNone(self): + if not HAS_NUMPY: + return + tab = Table(['pred_bfactors','ref_distances'], 'ff', + ref_distances=[None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, 2.445, 2.405, 2.361, 2.124, 1.957, 1.897, 1.422, 1.348, 1.247, 1.165, 1.153, 1.011, 0.992, 0.885, 0.852, 0.775, 0.757, 0.755, 0.735, 0.71, 0.656, 0.636, 0.609, 0.607, 0.604, 0.595, 0.572, 0.549, 0.458, 0.438, 0.41, 0.345, 0.304, 0.254, 0.241, 0.227, 2.68, 1.856, 1.312, 0.453], + pred_bfactors=[1.85000, 2.01000, 2.12000, 2.14000, 2.15000, 2.18000, 2.20000, 2.26000, 2.28000, 2.31000, 2.37000, 2.38000, 2.39000, 2.39000, 2.43000, 2.43000, 2.49000, 2.51000, 2.56000, 2.58000, 2.65000, 2.67000, 2.72000, 2.75000, 2.77000, 2.81000, 2.91000, 2.95000, 3.09000, 3.12000, 3.25000, 3.30000, 3.33000, 3.38000, 3.39000, 3.41000, 3.41000, 3.45000, 3.57000, 3.59000, 3.64000, 3.76000, 3.76000, 3.92000, 3.95000, 3.95000, 4.05000, 4.06000, 4.07000, 4.14000, 4.14000, 4.18000, 4.24000, 4.28000, 4.40000, 4.43000, 4.43000, 4.48000, 4.50000, 4.51000, 4.54000, 4.63000, 4.64000, 4.79000, 4.93000, 5.07000, 5.12000, 5.20000, 5.41000, 5.42000, 5.44000, 5.52000, 5.68000, 5.78000, 5.80000, 5.93000, 6.11000, 6.31000, 6.50000, 6.53000, 6.55000, 6.60000, 6.73000, 6.79000, 6.81000, 7.44000, 8.45000, 8.81000, 9.04000, 9.29000, 9.30000, 10.99000, 11.42000, 12.55000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 99.99000, 99.99000, 99.99000, 99.99000]) + + auc = tab.ComputeEnrichmentAUC(score_col='pred_bfactors', class_col='ref_distances') + self.assertAlmostEqual(auc, 0.50714285714285) + + # when removing all None lines, no true positive is left + auc = tab.ComputeEnrichmentAUC(score_col='ref_distances', class_col='pred_bfactors') + self.assertEqual(auc, None) + + # when increasing the cutoff, we have again true positives + auc = tab.ComputeEnrichmentAUC(score_col='ref_distances', class_col='pred_bfactors', class_cutoff=60) + self.assertAlmostEqual(auc, 0.52013888888) + def testCalcEnrichmentAUC(self): if not HAS_NUMPY: return @@ -1205,6 +1281,24 @@ class TestTable(unittest.TestCase): #self.CompareImages(img1, img2) #pl.show() + def testCalcROCAUCwithNone(self): + if not HAS_NUMPY: + return + tab = Table(['pred_bfactors','ref_distances'], 'ff', + ref_distances=[None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, 2.445, 2.405, 2.361, 2.124, 1.957, 1.897, 1.422, 1.348, 1.247, 1.165, 1.153, 1.011, 0.992, 0.885, 0.852, 0.775, 0.757, 0.755, 0.735, 0.71, 0.656, 0.636, 0.609, 0.607, 0.604, 0.595, 0.572, 0.549, 0.458, 0.438, 0.41, 0.345, 0.304, 0.254, 0.241, 0.227, 2.68, 1.856, 1.312, 0.453], + pred_bfactors=[1.85000, 2.01000, 2.12000, 2.14000, 2.15000, 2.18000, 2.20000, 2.26000, 2.28000, 2.31000, 2.37000, 2.38000, 2.39000, 2.39000, 2.43000, 2.43000, 2.49000, 2.51000, 2.56000, 2.58000, 2.65000, 2.67000, 2.72000, 2.75000, 2.77000, 2.81000, 2.91000, 2.95000, 3.09000, 3.12000, 3.25000, 3.30000, 3.33000, 3.38000, 3.39000, 3.41000, 3.41000, 3.45000, 3.57000, 3.59000, 3.64000, 3.76000, 3.76000, 3.92000, 3.95000, 3.95000, 4.05000, 4.06000, 4.07000, 4.14000, 4.14000, 4.18000, 4.24000, 4.28000, 4.40000, 4.43000, 4.43000, 4.48000, 4.50000, 4.51000, 4.54000, 4.63000, 4.64000, 4.79000, 4.93000, 5.07000, 5.12000, 5.20000, 5.41000, 5.42000, 5.44000, 5.52000, 5.68000, 5.78000, 5.80000, 5.93000, 6.11000, 6.31000, 6.50000, 6.53000, 6.55000, 6.60000, 6.73000, 6.79000, 6.81000, 7.44000, 8.45000, 8.81000, 9.04000, 9.29000, 9.30000, 10.99000, 11.42000, 12.55000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 50.00000, 99.99000, 99.99000, 99.99000, 99.99000]) + + auc = tab.ComputeROCAUC(score_col='pred_bfactors', class_col='ref_distances') + self.assertAlmostEqual(auc, 0.55714285714285705) + + # when removing all None lines, no true positive is left + auc = tab.ComputeROCAUC(score_col='ref_distances', class_col='pred_bfactors') + self.assertEqual(auc, None) + + # when increasing the cutoff, we have again true positives + auc = tab.ComputeROCAUC(score_col='ref_distances', class_col='pred_bfactors', class_cutoff=60) + self.assertAlmostEqual(auc, 0.701388888888888) + def testCalcROCAUC(self): if not HAS_NUMPY: return @@ -1354,7 +1448,52 @@ class TestTable(unittest.TestCase): self.assertRaises(RuntimeError, tab.GetOptimalPrefactors, 'c','a','b',weight='d') self.assertRaises(RuntimeError, tab.GetOptimalPrefactors, 'c',weights='d') - + + def testGaussianSmooth(self): + tab = Table(['a','b','c','d','e','f'],'fffffi', + a=[0.5,1.0,2.0,3.0,2.5,1.0,0.5,2.3,1.0], + b=[0.5,1.0,2.0,3.0,2.5,1.0,0.5,2.3,1.0], + c=[0.5,1.0,2.0,3.0,2.5,1.0,0.5,2.3,1.0], + d=[0.5,1.0,2.0,3.0,2.5,1.0,0.5,2.3,1.0], + e=[0.5,1.0,2.0,3.0,2.5,1.0,0.5,2.3,1.0], + f=[2,6,5,3,8,7,4,4,4]) + + tab.GaussianSmooth('a') + tab.GaussianSmooth('b', std=2.0) + tab.GaussianSmooth('c', padding='wrap') + tab.GaussianSmooth('d', padding='constant') + tab.GaussianSmooth('e', padding='constant',c=3.0) + tab.GaussianSmooth('f') + + ref_list=[] + + ref_list.append([0.74729766,1.20875404,1.93459464,2.39849076,2.11504816, + 1.42457403,1.20524937,1.41025075,1.3557406]) + ref_list.append([1.23447249,1.41295267,1.65198705,1.79959835,1.78131778, + 1.64501718,1.49728102,1.40589715,1.37147629]) + ref_list.append([0.9315564,1.24131027,1.93698455,2.39855767,2.11504816, + 1.42450711,1.20285946,1.37769451,1.17148186]) + ref_list.append([0.5630556,1.17705895,1.93224488,2.39842384,2.11504816, + 1.4244402,1.2005097,1.34599942,0.9872398 ]) + ref_list.append([1.46464039,1.35272941,1.94594196,2.39882533,2.11504816, + 1.42484169,1.21420677,1.52166988,1.88882459]) + ref_list.append([3,4,4,5,6,6,4,4,4]) + + tab_list=[[],[],[],[],[],[]] + + for row in tab.rows: + for i,v in enumerate(row): + tab_list[i].append(v) + + for i in range(len(ref_list[0])): + self.assertAlmostEquals(tab_list[0][i],ref_list[0][i]) + self.assertAlmostEquals(tab_list[1][i],ref_list[1][i]) + self.assertAlmostEquals(tab_list[2][i],ref_list[2][i]) + self.assertAlmostEquals(tab_list[3][i],ref_list[3][i]) + self.assertAlmostEquals(tab_list[4][i],ref_list[4][i]) + self.assertAlmostEquals(tab_list[5][i],ref_list[5][i]) + + def testIsEmpty(self): tab = Table() self.assertTrue(tab.IsEmpty()) diff --git a/modules/config/CMakeLists.txt b/modules/config/CMakeLists.txt index c7cdc9468303279890c5a9a84ce2d9aae4fae4ad..4f7e645ae21730204495c46ce91bc624bf4b28bb 100644 --- a/modules/config/CMakeLists.txt +++ b/modules/config/CMakeLists.txt @@ -74,6 +74,4 @@ set(VERSION_HH_FILE "${CMAKE_CURRENT_SOURCE_DIR}/version.hh") configure_file(config.hh.in ${CONFIG_HH_FILE}) configure_file(version.hh.in ${VERSION_HH_FILE}) add_custom_target(ost_config) -stage_headers("${OST_CONFIG_HEADERS}" "ost" - "ost_config" "" "ost") -install(FILES ${OST_CONFIG_HEADERS} DESTINATION include/ost) +stage_and_install_headers("${OST_CONFIG_HEADERS}" "ost" "ost_config") diff --git a/modules/doc/table.rst b/modules/doc/table.rst index 19d9c3c278a08f908fe7c8d712d4881ac4774aab..f3af1277017dc3d8a20639362e32174a673734c7 100644 --- a/modules/doc/table.rst +++ b/modules/doc/table.rst @@ -59,11 +59,13 @@ Functions You Might be Interested In :meth:`~ost.table.Table.AddRow` add a row to the table :meth:`~ost.table.Table.AddCol` add a column to the table :meth:`~ost.table.Table.RemoveCol` remove a column from the table +:meth:`~ost.table.Table.RenameCol` rename a column :meth:`~ost.table.Table.Extend` append a table to the end of another table :meth:`~ost.table.Merge` merge two tables together :meth:`~ost.table.Table.Sort` sort table by column :meth:`~ost.table.Table.Filter` filter table by values :meth:`~ost.table.Table.Zip` extract multiple columns at once +:meth:`~ost.table.Table.SearchColNames` search for matching column names **Input/Output** :meth:`~ost.table.Table.Save` save a table to a file @@ -93,6 +95,8 @@ Functions You Might be Interested In :meth:`~ost.table.Table.PlotHistogram` Plot data as histogram :meth:`~ost.table.Table.PlotROC` Plot receiver operating characteristics (ROC) :meth:`~ost.table.Table.PlotEnrichment` Plot enrichment +:meth:`~ost.table.Table.PlotHexbin` Hexagonal density plot +:meth:`~ost.table.Table.PlotBar` Bar plot ============================================= ============================================ @@ -105,4 +109,4 @@ The Table class :members: :undoc-members: SUPPORTED_TYPES -.. autofunction:: ost.table.Merge \ No newline at end of file +.. autofunction:: ost.table.Merge diff --git a/modules/geom/src/transform.cc b/modules/geom/src/transform.cc index d2a07f6ab0a701d0194bdcd1a4d300f039017f1f..9c00d5e8c4fc2aa1cc3b5b71e498e99585aa0ee0 100644 --- a/modules/geom/src/transform.cc +++ b/modules/geom/src/transform.cc @@ -18,7 +18,6 @@ //------------------------------------------------------------------------------ #include <ost/config.hh> -#include <ost/log.hh> #include "transform.hh" #include "vecmat3_op.hh" @@ -40,6 +39,13 @@ void Transform::SetMatrix(const Mat4& m) { tm_=m; ttm_ = Transpose(tm_); + try { + itm_ = Invert(tm_); + } catch (GeomException& e) { + std::cerr << "caught GeomException in Transform::SetMatrix: " << e.what() << std::endl; + std::cerr << m << std::endl; + itm_=geom::Mat4(); + } update_components(); } @@ -151,6 +157,18 @@ Vec4 Transform::Apply(const Vec4& v) const return nrvo; } +Vec3 Transform::ApplyInverse(const Vec3& v) const +{ + Vec3 nrvo(itm_*Vec4(v)); + return nrvo; +} + +Vec4 Transform::ApplyInverse(const Vec4& v) const +{ + Vec4 nrvo=itm_*v; + return nrvo; +} + geom::AlignedCuboid Transform::Apply(const geom::AlignedCuboid& c) const { geom::Vec3 cmin=c.GetMin(); @@ -168,6 +186,13 @@ geom::AlignedCuboid Transform::Apply(const geom::AlignedCuboid& c) const return geom::AlignedCuboid(minc,maxc); } +Transform Transform::Apply(const Transform& tf) const +{ + Transform nrvo(*this); + nrvo.SetMatrix(tf.GetMatrix()*nrvo.GetMatrix()); + return nrvo; +} + /* The order of the transformations given herein is conceptually "backward" as they are applied to a vertex, because the left-right @@ -189,14 +214,14 @@ void Transform::update_tm() { tm_ = Mat4(1.0,0.0,0.0,trans_[0], - 0.0,1.0,0.0,trans_[1], - 0.0,0.0,1.0,trans_[2], - 0.0,0.0,0.0,1.0) * + 0.0,1.0,0.0,trans_[1], + 0.0,0.0,1.0,trans_[2], + 0.0,0.0,0.0,1.0) * Mat4(rot_) * Mat4(1.0,0.0,0.0,-cen_[0], - 0.0,1.0,0.0,-cen_[1], - 0.0,0.0,1.0,-cen_[2], - 0.0,0.0,0.0,1.0); + 0.0,1.0,0.0,-cen_[1], + 0.0,0.0,1.0,-cen_[2], + 0.0,0.0,0.0,1.0); ttm_ = Transpose(tm_); // TODO: calculate from rot, cen and trans try { @@ -209,11 +234,11 @@ void Transform::update_tm() void Transform::update_components() { + // there is no way to extract the centering component + // so we just get a rotation and translation rot_ = tm_.ExtractRotation(); - cen_ = tm_.ExtractTranslation(); - trans_[0] = tm_(3,0); - trans_[1] = tm_(3,1); - trans_[2] = tm_(3,2); + trans_ = tm_.ExtractTranslation(); + cen_ = Vec3(0,0,0); } } // ns diff --git a/modules/geom/src/transform.hh b/modules/geom/src/transform.hh index 997f763950d7f94a7f7c6df35ea11f210b40847d..6965c48437dd5b4c041aabf46eb705ec87bd9ec4 100644 --- a/modules/geom/src/transform.hh +++ b/modules/geom/src/transform.hh @@ -39,7 +39,10 @@ namespace geom { class DLLEXPORT_OST_GEOM Transform { public: Transform(); - + + /// \brief reset to identity + void Reset() {*this=Transform();} + /// \brief retrieve transformation matrix Mat4 GetMatrix() const {return tm_;} /// \brief retrieve transposed transformation matrix @@ -78,10 +81,18 @@ public: void SetTrans(const Vec3& t); Vec3 GetTrans() const; //@} - + + // apply to a vec3 and return result Vec3 Apply(const Vec3& v) const; + // apply to a vec4 and return result Vec4 Apply(const Vec4& v) const; + // apply inverse to a vec3 and return result + Vec3 ApplyInverse(const Vec3& v) const; + // apply inverse to a vec4 and return result + Vec4 ApplyInverse(const Vec4& v) const; + // apply to an aligned cuboid and return result AlignedCuboid Apply(const AlignedCuboid& c) const; + Transform Apply(const Transform& tf) const; private: Mat3 rot_; diff --git a/modules/geom/src/vec3.hh b/modules/geom/src/vec3.hh index 7b4bb5b33fd33cccfe285f6d602bfa8d968bb687..c1cde046c0174c7571701ca6ee82e9645ccc41c8 100644 --- a/modules/geom/src/vec3.hh +++ b/modules/geom/src/vec3.hh @@ -239,11 +239,15 @@ namespace geom { inline Vec3::Vec3(const Vec4& v): x(v.x), y(v.y), z(v.z) { if (std::fabs(v.w)<1e-10) { - throw DivideByZeroException(); + // it is better to ignore very small w and to simply assume + // that this is not a homogeneous coordinate rather than + // throwing an exception + //throw DivideByZeroException(); + } else { + x/=v.w; + y/=v.w; + z/=v.w; } - x/=v.w; - y/=v.w; - z/=v.w; } } // namespace geom diff --git a/modules/geom/tests/test_transform.cc b/modules/geom/tests/test_transform.cc index 5f4a543fd8ecfa21c3a3ac78a0a4b88d24ee36f9..ae27fd594b71432bfa271fbcf5fecce52c9e5594 100644 --- a/modules/geom/tests/test_transform.cc +++ b/modules/geom/tests/test_transform.cc @@ -28,7 +28,7 @@ using namespace geom; BOOST_AUTO_TEST_SUITE( geom_base ); -BOOST_AUTO_TEST_CASE(test_transform) +BOOST_AUTO_TEST_CASE(test_transform_essentials) { Transform tf; @@ -37,12 +37,55 @@ BOOST_AUTO_TEST_CASE(test_transform) BOOST_CHECK_EQUAL(tf.GetTrans(), geom::Vec3()); BOOST_CHECK_EQUAL(tf.GetCenter(), geom::Vec3()); - geom::Mat4 mat = geom::Mat4(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16); - tf.SetMatrix(mat); - BOOST_CHECK_EQUAL(tf.GetMatrix(), mat); - BOOST_CHECK_EQUAL(tf.GetRot(), geom::Mat3(1,2,3,5,6,7,9,10,11)); - BOOST_CHECK_EQUAL(tf.GetCenter(), geom::Vec3(4,8,12)); - BOOST_CHECK_EQUAL(tf.GetTrans(), geom::Vec3(13,14,15)); + Mat3 rot=AxisRotation(Vec3(0.4,1.0,-0.8),2.13253); + Vec3 cen(0.5,1.0,2.2); + Vec3 tra(10,20,30); + tf.SetRot(rot); + tf.SetTrans(tra); + tf.SetCenter(cen); + + Mat4 tmat = + geom::Mat4(1.0,0.0,0.0,tra[0], + 0.0,1.0,0.0,tra[1], + 0.0,0.0,1.0,tra[2], + 0.0,0.0,0.0,1.0) * + geom::Mat4(rot) * + geom::Mat4(1.0,0.0,0.0,-cen[0], + 0.0,1.0,0.0,-cen[1], + 0.0,0.0,1.0,-cen[2], + 0.0,0.0,0.0,1.0); + + BOOST_CHECK_EQUAL(tf.GetRot(), rot); + BOOST_CHECK_EQUAL(tf.GetCenter(), cen); + BOOST_CHECK_EQUAL(tf.GetTrans(), tra); + + Transform tf2; + tf2.SetMatrix(tf.GetMatrix()); + BOOST_CHECK_EQUAL(tf2.GetRot(), rot); + BOOST_CHECK_EQUAL(tf2.GetCenter(), Vec3(0,0,0)); + BOOST_CHECK_EQUAL(tf2.GetTrans(), rot*-cen+tra); +} + +BOOST_AUTO_TEST_CASE(test_transform_apply_transform) +{ + Transform t1,t2; + Mat3 rm1=AxisRotation(Vec3(0.4,1.0,-0.8),2.13253); + Mat3 rm2=AxisRotation(Vec3(2.4,-0.1,3.8),-1.123); + t1.SetRot(rm1); + t1.SetCenter(Vec3(0.5,1.0,2.2)); + t1.SetTrans(Vec3(10,20,30)); + t2.SetRot(rm2); + t2.SetCenter(Vec3(1.3,2.7,-1.1)); + t2.SetTrans(Vec3(-40,-60,80)); + + Mat4 mat1=t1.GetMatrix(); + Mat4 mat2=t2.GetMatrix(); + Mat4 mat12=mat2*mat1; + + Transform t3 = t1.Apply(t2); + Mat4 mat3=t3.GetMatrix(); + for(int i=0;i<16;++i) BOOST_CHECK_CLOSE(mat3.Data()[i],mat12.Data()[i],1e-6); + } BOOST_AUTO_TEST_SUITE_END(); diff --git a/modules/geom/tests/test_vec3.cc b/modules/geom/tests/test_vec3.cc index 9e3e4d9485c379293b59bf454d0befce87181737..3964daf007ade2efcb4db4b0d97547761135fbd5 100644 --- a/modules/geom/tests/test_vec3.cc +++ b/modules/geom/tests/test_vec3.cc @@ -58,8 +58,8 @@ BOOST_AUTO_TEST_CASE(init_vec3) // conversion from vec4 Vec3 v6(Vec4(0.4,1.2,4.0,2.0)); BOOST_CHECK(match(v6,0.2,0.6,2.0)); - BOOST_CHECK_THROW( Vec3(Vec4(1.0,1.0,1.0,0.0)), DivideByZeroException); + BOOST_CHECK(match(Vec3(Vec4(2.0,1.0,3.0,0.0)),2.0,1.0,3.0)); } BOOST_AUTO_TEST_CASE(access_vec3) diff --git a/modules/gfx/pymod/CMakeLists.txt b/modules/gfx/pymod/CMakeLists.txt index 0ee14167c4f19232a7e4ecbdda746ab6c1b6a2a9..cdc4abb2158de61e9639cc50d839fc760c28e30d 100644 --- a/modules/gfx/pymod/CMakeLists.txt +++ b/modules/gfx/pymod/CMakeLists.txt @@ -15,6 +15,7 @@ set(OST_GFX_PYMOD_SOURCES export_color_ops.cc export_glwin_base.cc export_exporter.cc + export_bitmap.cc ) if (ENABLE_IMG) @@ -29,4 +30,4 @@ set(GRADIENT_FILE copy_if_different("${CMAKE_CURRENT_SOURCE_DIR}" "${STAGE_DIR}/share/openstructure/scene" "${GRADIENT_FILE}" "PRESET GRADIENTS" _ost_gfx) -install(FILES ${GRADIENT_FILE} DESTINATION "share/openstructure/scene") \ No newline at end of file +install(FILES ${GRADIENT_FILE} DESTINATION "share/openstructure/scene") diff --git a/modules/gfx/pymod/export_bitmap.cc b/modules/gfx/pymod/export_bitmap.cc new file mode 100644 index 0000000000000000000000000000000000000000..d8e944d21462cfaa90d72b7c99920882c6887722 --- /dev/null +++ b/modules/gfx/pymod/export_bitmap.cc @@ -0,0 +1,46 @@ +//------------------------------------------------------------------------------ +// This file is part of the OpenStructure project <www.openstructure.org> +// +// Copyright (C) 2008-2011 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> +using namespace boost::python; + +#include <ost/gfx/bitmap_io.hh> +using namespace ost; +using namespace ost::gfx; + +namespace { + unsigned int get_width(const Bitmap& bm) {return bm.width;} + void set_width(Bitmap& bm, unsigned int w) {bm.width=w;} + unsigned int get_height(const Bitmap& bm) {return bm.height;} + void set_height(Bitmap& bm, unsigned int w) {bm.height=w;} + + Bitmap import1(const std::string& n) {return ImportBitmap(n);} + Bitmap import2(const std::string& n, std::string e) {return ImportBitmap(n,e);} +} + +void export_bitmap() +{ + class_<Bitmap>("Bitmap",init<>()) + .add_property("width",get_width,set_width) + .add_property("height",get_height,set_height) + ; + + def("ExportBitmap",ExportBitmap); + def("ImportBitmap",import1); + def("ImportBitmap",import2); +} diff --git a/modules/gfx/pymod/export_gfx_obj.cc b/modules/gfx/pymod/export_gfx_obj.cc index 5f9ad7d1a4ecfc29a4b1aadf18b42c4d4f81e6e0..07d845636676fbd2c381ee1bbab25a4bf8aa0ca4 100644 --- a/modules/gfx/pymod/export_gfx_obj.cc +++ b/modules/gfx/pymod/export_gfx_obj.cc @@ -155,6 +155,8 @@ void export_GfxObj() .def("SetOpacity",&GfxObjBase::SetOpacity) .def("GetOpacity",&GfxObjBase::GetOpacity) .add_property("opacity",&GfxObjBase::GetOpacity,&GfxObjBase::SetOpacity) + .add_property("solid",&GfxObjBase::GetSolid,&GfxObjBase::SetSolid) + .add_property("solid_color",&GfxObjBase::GetSolidColor,&GfxObjBase::SetSolidColor) COLOR_BY_DEF() ; diff --git a/modules/gfx/pymod/export_scene.cc b/modules/gfx/pymod/export_scene.cc index 39d1fde6bde504a407dea60247b7cadf01fb5b8a..23ff9d687b497960588b169884690ff6a071243e 100644 --- a/modules/gfx/pymod/export_scene.cc +++ b/modules/gfx/pymod/export_scene.cc @@ -65,6 +65,10 @@ geom::AlignedCuboid scene_get_bb3(Scene* scene, const geom::Transform& tf) return scene->GetBoundingBox(tf); } +void (Scene::*scene_set_bg1)(const Color&) = &Scene::SetBackground; +void (Scene::*scene_set_bg2)(const Gradient&) = &Scene::SetBackground; +void (Scene::*scene_set_bg3)(const Bitmap&) = &Scene::SetBackground; + } // anon ns @@ -124,10 +128,12 @@ void export_Scene() .def("Resize", &Scene::Resize) .def("HasNode", &Scene::HasNode) .def("GetBackground", &Scene::GetBackground) - .def("SetBackground", &Scene::SetBackground) + .def("SetBackground", scene_set_bg1) + .def("SetBackground", scene_set_bg2) + .def("SetBackground", scene_set_bg3) .add_property("bg", &Scene::GetBackground, - &Scene::SetBackground) + scene_set_bg1) .def("GetProjection",&Scene::GetProjection) .add_property("projection",&Scene::GetProjection) .def("GetInvertedProjection",&Scene::GetInvertedProjection) diff --git a/modules/gfx/pymod/gradients.xml b/modules/gfx/pymod/gradients.xml index e3e1fbd0cad68995f30fa7b445f108b05eb31210..bd79d60947eefc96fcf343f930990cca004d4b9d 100644 --- a/modules/gfx/pymod/gradients.xml +++ b/modules/gfx/pymod/gradients.xml @@ -70,6 +70,10 @@ <Gradient hsv_color="1" hsv_mode="1" Name="RED_TO_BLUE_HSV">2 0.0 1 1 1 1 1.0 0.66666667 1 1 1 +</Gradient> +<Gradient Name="BIOZENTRUM">2 + 0.0 0.901960784314 0.0 0.392156862745 1 + 1.0 0.352941176471 0.176470588235 0.529411764706 1 </Gradient> </Gradients> </EMDataInfo> diff --git a/modules/gfx/pymod/wrap_gfx.cc b/modules/gfx/pymod/wrap_gfx.cc index 28229edf12ada259a25443f363d43db51199291d..b28c496597e9ae55489a1a0930fdfe2b00fcc620 100644 --- a/modules/gfx/pymod/wrap_gfx.cc +++ b/modules/gfx/pymod/wrap_gfx.cc @@ -37,6 +37,7 @@ extern void export_primlist(); extern void export_primitives(); extern void export_color(); extern void export_gradient(); +extern void export_bitmap(); extern void export_Exporter(); #if OST_IMG_ENABLED @@ -73,6 +74,7 @@ BOOST_PYTHON_MODULE(_ost_gfx) export_primlist(); export_color(); export_gradient(); + export_bitmap(); enum_<RenderMode::Type>("RenderMode") .value("SIMPLE",RenderMode::SIMPLE) diff --git a/modules/gfx/src/bitmap_io.cc b/modules/gfx/src/bitmap_io.cc index 6d36daaa1c339f8c4e995e90dc07f81c0cb10bf7..ab42f9de5a67242ee9edf51a705c6cec4a078121 100644 --- a/modules/gfx/src/bitmap_io.cc +++ b/modules/gfx/src/bitmap_io.cc @@ -21,15 +21,19 @@ */ #include <vector> +#include <sstream> #define ZLIB_WINAPI #include <png.h> #include <ost/log.hh> +#include <ost/message.hh> #include "bitmap_io.hh" namespace ost { namespace gfx { +namespace { + void export_png(const String& filename, unsigned int width, unsigned int height, unsigned char* data) { FILE *fp; @@ -181,15 +185,38 @@ Bitmap import_png(const String& filename) return bm; } -void BitmapExport(const String& fname, const String& ext, unsigned int width, unsigned int height,unsigned char* data) +std::string get_ext(const std::string& fname) { - if(ext==".png") export_png(fname,width,height,data); + int d_index=fname.rfind('.'); + if (d_index==-1) { + return ""; + } + return fname.substr(d_index+1); +} + +} + +void ExportBitmap(const String& fname, std::string ext, unsigned int width, unsigned int height,unsigned char* data) +{ + if(ext.empty()) ext=get_ext(fname); + if(ext=="png") { + export_png(fname,width,height,data); + } else { + std::ostringstream msg; + msg << "unsupported bitmap format [" << ext << "]"; + throw Error(msg.str()); + } } -Bitmap BitmapImport(const String& fname, const String& ext) +Bitmap ImportBitmap(const String& fname, std::string ext) { - if(ext==".png") { + if(ext.empty()) ext=get_ext(fname); + if(ext=="png") { return import_png(fname); + } else { + std::ostringstream msg; + msg << "unsupported bitmap format [" << ext << "]"; + throw Error(msg.str()); } return Bitmap(); } diff --git a/modules/gfx/src/bitmap_io.hh b/modules/gfx/src/bitmap_io.hh index afddc220bc6f91f3d60507b1d8fe1d47341292cf..dacb9dbe36b95a32c6d9b8273999ebbac7efe8eb 100644 --- a/modules/gfx/src/bitmap_io.hh +++ b/modules/gfx/src/bitmap_io.hh @@ -32,6 +32,7 @@ namespace ost { namespace gfx { // very rudimentary bitmap support +// TODO: gl tex mapping association struct Bitmap { /* @@ -46,9 +47,9 @@ struct Bitmap boost::shared_array<unsigned char> data; }; -void BitmapExport(const String& fname, const String& ext, unsigned int width, unsigned int height,unsigned char* data); +void DLLEXPORT_OST_GFX ExportBitmap(const String& fname, std::string ext, unsigned int width, unsigned int height,unsigned char* data); -Bitmap BitmapImport(const String& fname, const String& ext); +Bitmap DLLEXPORT_OST_GFX ImportBitmap(const String& fname, std::string ext=""); }} // ns diff --git a/modules/gfx/src/entity.hh b/modules/gfx/src/entity.hh index 112a7ac4d8f5b5dbdd6db517a673b9ded7180a34..d3fe0ad928855e1c6fe41b40943a8439b50996fe 100644 --- a/modules/gfx/src/entity.hh +++ b/modules/gfx/src/entity.hh @@ -90,7 +90,7 @@ public: RenderMode::Type m, const mol::EntityView& ev); - virtual geom::AlignedCuboid GetBoundingBox(bool use_global=false) const; + virtual geom::AlignedCuboid GetBoundingBox(bool use_tf=false) const; // ProcessLimits uses the default implementation of bounding box diff --git a/modules/gfx/src/gfx_object.cc b/modules/gfx/src/gfx_object.cc index f7e3b06a5af9a5b1962156db728b4556e331c98c..63003cd5bce9481772ed5d8f3f1e8aa919e2e7c8 100644 --- a/modules/gfx/src/gfx_object.cc +++ b/modules/gfx/src/gfx_object.cc @@ -64,6 +64,8 @@ GfxObj::GfxObj(const String& name): #else outline_mode_(1), #endif + solid_(false), + solid_color_(RGB(0.7,0.7,0.7)), c_ops_(), labels_(), use_occlusion_(false) @@ -128,6 +130,8 @@ void GfxObj::RenderGL(RenderPass pass) // there really needs to be a central place // where the va attributes are re-applied va_.SetOpacity(opacity_); + va_.SetSolid(solid_); + va_.SetSolidColor(solid_color_); } } if(IsVisible()) { @@ -375,6 +379,20 @@ void GfxObj::SetOpacity(float o) Scene::Instance().RequestRedraw(); } +void GfxObj::SetSolid(bool f) +{ + solid_=f; + va_.SetSolid(solid_); + Scene::Instance().RequestRedraw(); +} + +void GfxObj::SetSolidColor(const Color& c) +{ + solid_color_=c; + va_.SetSolidColor(solid_color_); + Scene::Instance().RequestRedraw(); +} + void GfxObj::ColorBy(const mol::EntityView& ev, const String& prop, const Gradient& g, float minv, float maxv) diff --git a/modules/gfx/src/gfx_object.hh b/modules/gfx/src/gfx_object.hh index fc906c35c9fdb7c563417c6785e5023d2dabe594..0b70065d7f820ca924ef07b3d2ad3005fe4e71b2 100644 --- a/modules/gfx/src/gfx_object.hh +++ b/modules/gfx/src/gfx_object.hh @@ -88,6 +88,11 @@ public: virtual Color GetOutlineExpandColor() const; virtual void SetOpacity(float f); virtual float GetOpacity() const {return opacity_;} + virtual void SetSolid(bool f); + virtual bool GetSolid() const {return solid_;} + virtual void SetSolidColor(const Color& c); + virtual Color GetSolidColor() const {return solid_color_;} + virtual void ColorBy(const mol::EntityView& ev, const String& prop, const Gradient& g, float minv, float maxv); @@ -242,6 +247,9 @@ public: bool outline_flag_; int outline_mode_; + bool solid_; + Color solid_color_; + boost::ptr_vector<gfx::ColorOp> c_ops_; TextPrimList labels_; diff --git a/modules/gfx/src/gfx_object_base.hh b/modules/gfx/src/gfx_object_base.hh index eb6c7c21743805e237377bc64e15ced0d61f3885..448de0cf2687781045e7b59bc72b145be0ee1c2d 100644 --- a/modules/gfx/src/gfx_object_base.hh +++ b/modules/gfx/src/gfx_object_base.hh @@ -117,6 +117,11 @@ class DLLEXPORT_OST_GFX GfxObjBase: public GfxNode /// \brief returns a value smaller than 1.0 if transparency is used in this object virtual float GetOpacity() const = 0; + virtual void SetSolid(bool f) = 0; + virtual bool GetSolid() const = 0; + virtual void SetSolidColor(const Color& c) = 0; + virtual Color GetSolidColor() const = 0; + /// \brief color each component based on the gradient-mapped property of /// the given entity virtual void ColorBy(const mol::EntityView& ev, diff --git a/modules/gfx/src/gfx_test_object.cc b/modules/gfx/src/gfx_test_object.cc index 5b238473055efe537db846838267fc842a85844f..7e60ab6d8657d35b44d2eb0840a0c0f7640ad76a 100644 --- a/modules/gfx/src/gfx_test_object.cc +++ b/modules/gfx/src/gfx_test_object.cc @@ -61,7 +61,7 @@ GfxTestObj::GfxTestObj(): bf::path ost_root_dir(ost_root); bf::path tex_file(ost_root_dir / "textures/test_texture.png"); - Texture tex(BitmapImport(tex_file.string(),".png")); + Texture tex(ImportBitmap(tex_file.string())); if(!tex.IsValid()) { LOG_ERROR("error loading " << tex_file.string()); } else { diff --git a/modules/gfx/src/gl_helper.hh b/modules/gfx/src/gl_helper.hh index dac567894edea06c8c6156dae1497dcd52c65f81..77346056346c4ec937b90dba4bebaedd9fe5fb59 100644 --- a/modules/gfx/src/gl_helper.hh +++ b/modules/gfx/src/gl_helper.hh @@ -39,12 +39,16 @@ Author: Juergen Haas #include <ost/log.hh> -inline void check_gl_error() +inline void check_gl_error(const std::string& m="") { + #ifndef NDEBUG GLenum error_code; if((error_code=glGetError())!=GL_NO_ERROR) { - LOG_VERBOSE("GL error: " << gluErrorString(error_code)); + if(!m.empty()) { + LOG_VERBOSE("GL error in [" << m << "]: " << gluErrorString(error_code)); + } } + #endif } inline void glVertex3v(double* v){ diff --git a/modules/gfx/src/gradient.cc b/modules/gfx/src/gradient.cc index c65261b16a60eb2deac7ecfcf41def8be63239f5..f1c93ffbbbfa7ff799073a49a3da5210fc688eb7 100644 --- a/modules/gfx/src/gradient.cc +++ b/modules/gfx/src/gradient.cc @@ -70,7 +70,7 @@ Color Gradient::GetColorAt(float t) const } uint c=0; - while (t>=stops_[c].t && c<stops_.size()) { + while (c<stops_.size() && t>=stops_[c].t) { ++c; } if (c==0) { diff --git a/modules/gfx/src/impl/fast_spheres.hh b/modules/gfx/src/impl/fast_spheres.hh index 2cef93d6561407b768586537851e5a5b83f7011a..72402ef9b36f81fca897f0a2484b39def3a7a932 100644 --- a/modules/gfx/src/impl/fast_spheres.hh +++ b/modules/gfx/src/impl/fast_spheres.hh @@ -30,7 +30,7 @@ namespace ost { namespace gfx { namespace impl { - class FastSphereRenderer { + class DLLEXPORT_OST_GFX FastSphereRenderer { public: struct VData { diff --git a/modules/gfx/src/impl/scene_fx.cc b/modules/gfx/src/impl/scene_fx.cc index de0000484bf41a13d91220a312e54013ac643922..a9ddbc4cd9f8fc7e7d235efae0c8ce390c422d71 100644 --- a/modules/gfx/src/impl/scene_fx.cc +++ b/modules/gfx/src/impl/scene_fx.cc @@ -224,6 +224,11 @@ void SceneFX::Preprocess() } } +bool SceneFX::WillPostprocess() const +{ + return shadow_flag || amb_occl_flag || depth_dark_flag || use_beacon; +} + void SceneFX::Postprocess() { if(!OST_GL_VERSION_2_0) return; @@ -235,10 +240,7 @@ void SceneFX::Postprocess() #endif } - if(!shadow_flag && !amb_occl_flag && !depth_dark_flag && !use_beacon) { - // no postprocessing is needed - return; - } + if(!WillPostprocess()) return; Viewport vp=Scene::Instance().GetViewport(); @@ -329,6 +331,18 @@ void SceneFX::Postprocess() glUniform1i(glGetUniformLocation(cpr,"dark_flag"),0); } + GLint fog; + glGetIntegerv(GL_FOG,&fog); + float znear=Scene::Instance().GetNear(); + float zfar=Scene::Instance().GetFar(); + float fnear=znear+Scene::Instance().GetFogNearOffset(); + float ffar=zfar+Scene::Instance().GetFogFarOffset(); + glUniform1i(glGetUniformLocation(cpr,"fog_flag"),fog); + glUniform1f(glGetUniformLocation(cpr,"depth_near"),znear); + glUniform1f(glGetUniformLocation(cpr,"depth_far"),zfar); + glUniform1f(glGetUniformLocation(cpr,"fog_far"),ffar); + glUniform1f(glGetUniformLocation(cpr,"fog_scale"),1.0f/(ffar-fnear)); + if(use_beacon) { prep_beacon(); } @@ -480,7 +494,11 @@ void SceneFX::prep_shadow_map() are first reverted, and then the light modelview and projection are applied, resulting (with the bias) in the proper 2D lookup into the shadow map */ - shadow_tex_mat_ = bias*pmat*ltrans.GetMatrix()*geom::Invert(Scene::Instance().GetTransform().GetMatrix())*geom::Invert(pmat2); + try { + shadow_tex_mat_ = bias*pmat*ltrans.GetMatrix()*geom::Invert(Scene::Instance().GetTransform().GetMatrix())*geom::Invert(pmat2); + } catch (geom::GeomException& e) { + LOG_DEBUG("SceneFX: caught matrix inversion exception in prep_shadow_map()"); + } } void SceneFX::prep_amb_occlusion() @@ -516,7 +534,12 @@ void SceneFX::prep_amb_occlusion() glMatrixMode(GL_TEXTURE); glPushMatrix(); - geom::Mat4 ipm(geom::Transpose(geom::Invert(geom::Transpose(geom::Mat4(pm))))); + geom::Mat4 ipm; + try { + ipm=(geom::Transpose(geom::Invert(geom::Transpose(geom::Mat4(pm))))); + } catch (geom::GeomException& e) { + LOG_DEBUG("SceneFX: caught matrix inversion exception in prep_amb_occlusion()"); + } glLoadMatrix(ipm.Data()); glMatrixMode(GL_MODELVIEW); @@ -638,7 +661,11 @@ void SceneFX::prep_beacon() glGetv(GL_PROJECTION_MATRIX, glpmat); geom::Mat4 pmat2(geom::Transpose(geom::Mat4(glpmat))); - beacon.mat = geom::Invert(Scene::Instance().GetTransform().GetMatrix())*geom::Invert(pmat2); + try { + beacon.mat = geom::Invert(Scene::Instance().GetTransform().GetMatrix())*geom::Invert(pmat2); + } catch (geom::GeomException& e) { + beacon.mat=geom::Mat4(); + } } void SceneFX::draw_beacon() diff --git a/modules/gfx/src/impl/scene_fx.hh b/modules/gfx/src/impl/scene_fx.hh index 3b8e1fa388b67ea0c51be27676b437875c0e7aa6..ad8d2a787c57a7b4e9eb1433fd5d8e1f4c63d173 100644 --- a/modules/gfx/src/impl/scene_fx.hh +++ b/modules/gfx/src/impl/scene_fx.hh @@ -53,6 +53,9 @@ public: void Preprocess(); // assumes scene has been drawn in the active framebuffer void Postprocess(); + + // returns true if the post-processing will run + bool WillPostprocess() const; void DrawTex(unsigned int w, unsigned int h, GLuint texid); diff --git a/modules/gfx/src/map_slab.cc b/modules/gfx/src/map_slab.cc index ae4a08629b4950c1836bd19fe2d53742e326a9ae..3af16f422257a6a1dea44aa2dd0da13bb20fd7b7 100644 --- a/modules/gfx/src/map_slab.cc +++ b/modules/gfx/src/map_slab.cc @@ -84,11 +84,12 @@ MapSlab::MapSlab(const String& name, const img::MapHandle& mh, const geom::Plane maxv_ = stat.GetMaximum(); } -geom::AlignedCuboid MapSlab::GetBoundingBox() const +geom::AlignedCuboid MapSlab::GetBoundingBox(bool use_tf) const { geom::Vec3 minc = plane_.At(-1.0,-1.0); geom::Vec3 maxc = plane_.At(1.0,1.0); - return geom::AlignedCuboid(minc,maxc); + geom::AlignedCuboid bb(minc,maxc); + return use_tf ? transform_.Apply(bb) : bb; } geom::Vec3 MapSlab::GetCenter() const diff --git a/modules/gfx/src/map_slab.hh b/modules/gfx/src/map_slab.hh index 8d27b975c3fc72bcc52d4ba5031e92b14a135e76..c38a88864a5fc129733571c2be34971ce73339fd 100644 --- a/modules/gfx/src/map_slab.hh +++ b/modules/gfx/src/map_slab.hh @@ -62,7 +62,7 @@ public: MapSlab(const String& name, const img::MapHandle& mh, const geom::Plane& p); - virtual geom::AlignedCuboid GetBoundingBox() const; + virtual geom::AlignedCuboid GetBoundingBox(bool use_tf=true) const; virtual geom::Vec3 GetCenter() const; virtual void CustomRenderGL(RenderPass pass); diff --git a/modules/gfx/src/prim_list.cc b/modules/gfx/src/prim_list.cc index e07820e6bc6c15af276b8a7012baa21b00545eb3..0c8589ea29837485a979443287b31f6be137fe74 100644 --- a/modules/gfx/src/prim_list.cc +++ b/modules/gfx/src/prim_list.cc @@ -54,7 +54,7 @@ void PrimList::Clear() this->FlagRebuild(); } -geom::AlignedCuboid PrimList::GetBoundingBox() const +geom::AlignedCuboid PrimList::GetBoundingBox(bool use_tf) const { if(points_.empty() && lines_.empty() && spheres_.empty() && cyls_.empty() && texts_.empty() && vas_.empty()) { return geom::AlignedCuboid(geom::Vec3(-1,-1,-1),geom::Vec3(1,1,1)); @@ -66,7 +66,8 @@ geom::AlignedCuboid PrimList::GetBoundingBox() const -std::numeric_limits<float>::max(), -std::numeric_limits<float>::max()); ProcessLimits(minc,maxc,geom::Transform()); - return geom::AlignedCuboid(minc,maxc); + geom::AlignedCuboid bb(minc,maxc); + return use_tf ? transform_.Apply(bb) : bb; } void PrimList::ProcessLimits(geom::Vec3& minc, geom::Vec3& maxc, diff --git a/modules/gfx/src/prim_list.hh b/modules/gfx/src/prim_list.hh index afc999a7febc930495d2f7620c7795295293be42..80eabe333a1b9264da03f015d1f423905aa36f56 100644 --- a/modules/gfx/src/prim_list.hh +++ b/modules/gfx/src/prim_list.hh @@ -61,7 +61,7 @@ class DLLEXPORT_OST_GFX PrimList: public GfxObj /// \brief create new prim list PrimList(const String& name); - virtual geom::AlignedCuboid GetBoundingBox() const; + virtual geom::AlignedCuboid GetBoundingBox(bool use_tf=true) const; virtual void ProcessLimits(geom::Vec3& minc, geom::Vec3& maxc, const geom::Transform& tf) const; diff --git a/modules/gfx/src/scene.cc b/modules/gfx/src/scene.cc index 2650eea5b09f5169bee74a9e984437573619aa3c..9212d8eab37f015b5019c25438efe75d162fb268 100644 --- a/modules/gfx/src/scene.cc +++ b/modules/gfx/src/scene.cc @@ -135,7 +135,12 @@ Scene::Scene(): stereo_iod_(4.0), stereo_distance_(0.0), scene_left_tex_(), - scene_right_tex_() + scene_right_tex_(), + bg_mode_(0), + update_bg_(false), + bg_grad_(), + bg_bm_(), + bg_tex_() { transform_.SetTrans(Vec3(0,0,-100)); } @@ -394,6 +399,8 @@ void Scene::InitGL(bool full) { LOG_VERBOSE("Scene: initializing GL state"); + check_gl_error(); // clear error flag + if(full) { LOG_INFO(glGetString(GL_RENDERER) << ", openGL version " << glGetString(GL_VERSION)); @@ -506,8 +513,10 @@ void Scene::InitGL(bool full) } if(full) { + LOG_DEBUG("Scene: initalizing textures"); glGenTextures(1,&scene_left_tex_); glGenTextures(1,&scene_right_tex_); + glGenTextures(1,&bg_tex_); } glEnable(GL_TEXTURE_2D); @@ -531,6 +540,14 @@ void Scene::InitGL(bool full) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE, GL_REPLACE); + glBindTexture(GL_TEXTURE_2D, bg_tex_); + glPixelStorei(GL_UNPACK_ALIGNMENT,1); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE, GL_REPLACE); + LOG_DEBUG("Scene: calling gl init for all objects"); GfxObjInitGL initgl; this->Apply(initgl); @@ -539,6 +556,8 @@ void Scene::InitGL(bool full) gl_init_=true; if(!def_shading_mode_.empty()) SetShadingMode(def_shading_mode_); + + check_gl_error("InitGL()"); } void Scene::RequestRedraw() @@ -556,6 +575,7 @@ void Scene::StatusMessage(const String& s) void Scene::SetBackground(const Color& c) { background_=c; + bg_mode_=0; if(gl_init_) { glClearColor(c.Red(),c.Green(),c.Blue(),c.Alpha()); SetFogColor(c); @@ -563,6 +583,65 @@ void Scene::SetBackground(const Color& c) } } +namespace { + void c2d(const Color& c, unsigned char* d) { + d[0]=static_cast<unsigned char>(c.GetRed()*255.0); + d[1]=static_cast<unsigned char>(c.GetGreen()*255.0); + d[2]=static_cast<unsigned char>(c.GetBlue()*255.0); + } +} + +void Scene::set_bg() +{ + static std::vector<unsigned char> data; + static const unsigned int grad_steps=64; + if(bg_mode_==1) { + LOG_DEBUG("Scene: setting background gradient"); + // gradient + glBindTexture(GL_TEXTURE_2D, bg_tex_); + data.resize(3*grad_steps); + float tf=1.0/static_cast<float>(grad_steps-1); + for(size_t i=0;i<grad_steps;++i) { + Color col=bg_grad_.GetColorAt(static_cast<float>(i)*tf); + c2d(col,&data[i*3]); + } + glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,1,grad_steps,0,GL_RGB,GL_UNSIGNED_BYTE,&data[0]); + } else if(bg_mode_==2) { + LOG_DEBUG("Scene: setting background bitmap"); + // bitmap + glBindTexture(GL_TEXTURE_2D, bg_tex_); + if(bg_bm_.channels==1) { + glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,bg_bm_.width,bg_bm_.height,0,GL_LUMINANCE,GL_UNSIGNED_BYTE,bg_bm_.data.get()); + } else if(bg_bm_.channels==3) { + glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,bg_bm_.width,bg_bm_.height,0,GL_RGB,GL_UNSIGNED_BYTE,bg_bm_.data.get()); + } else if(bg_bm_.channels==4) { + glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,bg_bm_.width,bg_bm_.height,0,GL_RGBA,GL_UNSIGNED_BYTE,bg_bm_.data.get()); + } else { + LOG_ERROR("Scene::SetBackground: unsupported bitmap channel count of " << bg_bm_.channels); + } + } +} + +void Scene::SetBackground(const Gradient& g) +{ + bg_grad_=g; + bg_mode_=1; + update_bg_=true; + RequestRedraw(); +} + +void Scene::SetBackground(const Bitmap& bm) +{ + if(bm.width==0 || bm.height==0) { + LOG_WARNING("Scene: background bitmap has invalid size (" << bm.width << "x" << bm.height << "), ignoring"); + return; + } + bg_bm_=bm; + bg_mode_=2; + update_bg_=true; + RequestRedraw(); +} + Color Scene::GetBackground() const { return background_; @@ -579,8 +658,8 @@ Viewport Scene::GetViewport() const void Scene::SetViewport(int w, int h) { - vp_width_=w; - vp_height_=h; + vp_width_=std::max<unsigned int>(1,w); + vp_height_=std::max<unsigned int>(1,h); aspect_ratio_=static_cast<float>(w)/static_cast<float>(h); if(!gl_init_) return; glViewport(0,0,w,h); @@ -726,6 +805,7 @@ void draw_lightdir(const Vec3& ldir, const geom::Transform& tf) void Scene::RenderGL() { + check_gl_error(); // clear error flag if(auto_autoslab_ || do_autoslab_) { do_autoslab(); do_autoslab_=false; @@ -738,7 +818,7 @@ void Scene::RenderGL() } else { render_scene(); } - check_gl_error(); + check_gl_error("RenderGL()"); } void Scene::Register(GLWinBase* win) @@ -1566,9 +1646,9 @@ void Scene::Export(const String& fname, unsigned int width, LOG_ERROR("Scene: no file extension specified"); return; } - String ext = fname.substr(d_index); - if(!(ext==".png")) { - LOG_ERROR("Scene: unknown file format (" << ext << ")"); + String ext = fname.substr(d_index+1); + if(ext!="png") { + LOG_ERROR("Scene::Export: unknown file format (" << ext << ")"); return; } @@ -1602,7 +1682,7 @@ void Scene::Export(const String& fname, unsigned int width, glReadBuffer(GL_BACK); LOG_DEBUG("Scene: calling bitmap export"); - BitmapExport(fname,ext,width,height,img_data.get()); + ExportBitmap(fname,ext,width,height,img_data.get()); // only switch back if it was not on to begin with if(of_flag) { @@ -1621,8 +1701,8 @@ void Scene::Export(const String& fname, bool transparent) LOG_ERROR("Scene: no file extension specified"); return; } - String ext = fname.substr(d_index); - if(ext!=".png") { + String ext = fname.substr(d_index+1); + if(ext!="png") { LOG_ERROR("Scene: unknown file format (" << ext << ")"); return; } @@ -1644,7 +1724,7 @@ void Scene::Export(const String& fname, bool transparent) boost::shared_array<uchar> img_data(new uchar[vp[2]*vp[3]*4]); glReadPixels(0,0,vp[2],vp[3],GL_RGBA,GL_UNSIGNED_BYTE,img_data.get()); glFinish(); - BitmapExport(fname,ext,vp[2],vp[3],img_data.get()); + ExportBitmap(fname,ext,vp[2],vp[3],img_data.get()); glPixelTransferf(GL_ALPHA_BIAS, 0.0); } @@ -1867,7 +1947,7 @@ void Scene::prep_glyphs() String ost_root =GetSharedDataPath(); bf::path ost_root_dir(ost_root); bf::path tex_file(ost_root_dir / "textures/glyph_texture.png"); - Bitmap bm = BitmapImport(tex_file.string(),".png"); + Bitmap bm = ImportBitmap(tex_file.string()); if(!bm.data) return; LOG_DEBUG("Scene: importing glyph tex with id " << glyph_tex_id_); @@ -1908,6 +1988,75 @@ void Scene::prep_blur() glFlush(); } +void Scene::render_bg() +{ + if(!gl_init_) return; + if(bg_mode_!=1 && bg_mode_!=2) return; + if(update_bg_) { + set_bg(); + check_gl_error("set_bg()"); + update_bg_=false; + } + + // setup state for simple texture quad +#if OST_SHADER_SUPPORT_ENABLED + Shader::Instance().PushProgram(); + Shader::Instance().Activate(""); +#endif + glPushAttrib(GL_ALL_ATTRIB_BITS); + glPushClientAttrib(GL_ALL_ATTRIB_BITS); + + glDisable(GL_DEPTH_TEST); + glDisable(GL_LIGHTING); + glDisable(GL_COLOR_MATERIAL); + glDisable(GL_FOG); + glDisable(GL_CULL_FACE); + glDisable(GL_BLEND); + glDisable(GL_LINE_SMOOTH); + glDisable(GL_POINT_SMOOTH); +#if defined(OST_GL_VERSION_2_0) + glDisable(GL_MULTISAMPLE); +#endif + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glOrtho(0,vp_width_,0,vp_height_,-1,1); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + + // draw bg texture quad + glEnable(GL_TEXTURE_2D); +#if OST_SHADER_SUPPORT_ENABLED + if(OST_GL_VERSION_2_0) { + glActiveTexture(GL_TEXTURE0); + } +#endif + glBindTexture(GL_TEXTURE_2D, bg_tex_); + // draw + glColor3f(0.0,0.0,0.0); + glBegin(GL_QUADS); + glTexCoord2f(0.0,0.0); glVertex2i(0,0); + glTexCoord2f(0.0,1.0); glVertex2i(0,vp_height_); + glTexCoord2f(1.0,1.0); glVertex2i(vp_width_,vp_height_); + glTexCoord2f(1.0,0.0); glVertex2i(vp_width_,0); + glEnd(); + + // restore all settings + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_TEXTURE_2D); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + glPopClientAttrib(); + glPopAttrib(); +#if OST_SHADER_SUPPORT_ENABLED + Shader::Instance().PopProgram(); +#endif + check_gl_error("render_bg()"); +} + void Scene::render_scene() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); @@ -1915,6 +2064,8 @@ void Scene::render_scene() glMatrixMode(GL_MODELVIEW); glLoadIdentity(); + render_bg(); + glMultMatrix(transform_.GetTransposedMatrix().Data()); #if OST_SHADER_SUPPORT_ENABLED diff --git a/modules/gfx/src/scene.hh b/modules/gfx/src/scene.hh index 4edc6663770bbdb3c047382f04e925474bd06baf..f6f4c87f1544b091d0e51777b7b254501ae4d22b 100644 --- a/modules/gfx/src/scene.hh +++ b/modules/gfx/src/scene.hh @@ -43,6 +43,8 @@ #include "gfx_prim.hh" #include "povray_fw.hh" #include "exporter_fw.hh" +#include "gradient.hh" +#include "bitmap_io.hh" namespace ost { namespace gfx { @@ -172,6 +174,8 @@ class DLLEXPORT_OST_GFX Scene { // \brief get the field of view float GetFOV() const; + float GetAspect() const {return aspect_ratio_;} + /// \brief offset between near clipping plane and start of fog void SetFogNearOffset(float o); @@ -333,6 +337,12 @@ class DLLEXPORT_OST_GFX Scene { /// \brief set background color void SetBackground(const Color& c); + /// \brief set background gradient + void SetBackground(const Gradient& g); + + /// \brief set background image + void SetBackground(const Bitmap& bm); + /// \brief get background color Color GetBackground() const; @@ -498,6 +508,7 @@ protected: void NodeAdded(const GfxNodeP& node); void RenderModeChanged(const String& name); + private: template <typename ACTION> @@ -568,6 +579,13 @@ private: Real stereo_iod_,stereo_distance_; unsigned int scene_left_tex_; unsigned int scene_right_tex_; + unsigned int bg_mode_; + bool update_bg_; + Gradient bg_grad_; + Bitmap bg_bm_; + unsigned int bg_tex_; + + void set_near(float n); void set_far(float f); @@ -576,10 +594,11 @@ private: void prep_glyphs(); void prep_blur(); void stereo_projection(int view); + void render_bg(); void render_scene(); void render_glow(); void render_stereo(); - + void set_bg(); void do_autoslab(); bool IsNameAvailable(const String& name) const; diff --git a/modules/gfx/src/shader.cc b/modules/gfx/src/shader.cc index 2a5e91ce25fa41c121ae12ecca5a6a2f08a82e68..3ed15cac334785fbb45e4d1b63fb91d62c70f599 100644 --- a/modules/gfx/src/shader.cc +++ b/modules/gfx/src/shader.cc @@ -28,6 +28,7 @@ #include <ost/platform.hh> #include <ost/log.hh> +#include "impl/scene_fx.hh" #include "glext_include.hh" #include "shader.hh" @@ -366,7 +367,11 @@ void Shader::UpdateState() glGetBooleanv(GL_LIGHT_MODEL_TWO_SIDE,&bresult); LOG_TRACE("setting two_sided flag to " << bresult); glUniform1i(glGetUniformLocation(current_program_,"two_sided_flag"),bresult); - glGetIntegerv(GL_FOG,&result); + if(impl::SceneFX::Instance().WillPostprocess()) { + result=0; + } else { + glGetIntegerv(GL_FOG,&result); + } LOG_TRACE("setting fog flag to " << result); glUniform1i(glGetUniformLocation(current_program_,"fog_flag"),result); glDisable(GL_COLOR_MATERIAL); diff --git a/modules/gfx/src/shader/scenefx_fs.glsl b/modules/gfx/src/shader/scenefx_fs.glsl index cb5c2313c77dced05f81fdd4854704ebbb4b9a6c..e328d2d086842e680c79329ab1fdaafd204d9cea 100644 --- a/modules/gfx/src/shader/scenefx_fs.glsl +++ b/modules/gfx/src/shader/scenefx_fs.glsl @@ -13,6 +13,11 @@ uniform float occl_mult; uniform bool dark_flag; uniform sampler2D dark_map; uniform float dark_mult; +uniform bool fog_flag; +uniform float depth_near; +uniform float depth_far; +uniform float fog_far; +uniform float fog_scale; // gl_TexCoord[0] comes from scenefx_vs, i.e. from post processing @@ -55,6 +60,15 @@ void main() if(dark_flag) { dark_factor=max(0.0,1.0-dark_mult*(1.0-texture2D(dark_map,gl_TexCoord[0].xy).r)); } - - gl_FragColor.rgb = shadow_factor*occl_factor*dark_factor*scene_color.rgb; + + float fog=1.0; + if(fog_flag) { + float z = 2.0*depth_near*depth_far/(-(depth*2.0-1.0)*(depth_far-depth_near)+depth_far+depth_near); + fog = clamp((fog_far-z) * fog_scale, 0.0, 1.0); + } + + gl_FragColor.rgb = mix(gl_Fog.color.rgb, + shadow_factor*occl_factor*dark_factor*scene_color.rgb, + fog); } + diff --git a/modules/gfx/src/vertex_array.cc b/modules/gfx/src/vertex_array.cc index b9c45e5a7ce54f274b2b1e0b029f100fd81772ec..155417b65e2cb2080bd6a5230ee30b936c3f5134 100644 --- a/modules/gfx/src/vertex_array.cc +++ b/modules/gfx/src/vertex_array.cc @@ -141,7 +141,6 @@ void IndexedVertexArray::SetOutlineMaterial(const Material& m) void IndexedVertexArray::SetOutlineExpandFactor(float f) { outline_exp_factor_=f;} void IndexedVertexArray::SetOutlineExpandColor(const Color& c) {outline_exp_color_=c;} - VertexID IndexedVertexArray::Add(const Vec3& vert, const Vec3& norm, const Color& col, @@ -494,7 +493,7 @@ void IndexedVertexArray::RenderGL() } else { glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE); } - if(cull_face_) { + if(cull_face_ && !solid_) { glEnable(GL_CULL_FACE); } else { glDisable(GL_CULL_FACE); @@ -699,6 +698,8 @@ void IndexedVertexArray::Reset() outline_mat_update_=true; outline_exp_factor_=0.1; outline_exp_color_=Color(0,0,0); + solid_=false; + solid_color_=RGB(1,1,1); draw_normals_=false; use_tex_=false; } @@ -1095,6 +1096,8 @@ void IndexedVertexArray::copy(const IndexedVertexArray& va) outline_mat_update_=true; outline_exp_factor_=va.outline_exp_factor_; outline_exp_color_=va.outline_exp_color_; + solid_=va.solid_; + solid_color_=va.solid_color_; draw_normals_=va.draw_normals_; use_tex_=va.use_tex_; } @@ -1174,6 +1177,14 @@ bool IndexedVertexArray::prep_buff() void IndexedVertexArray::draw_ltq(bool use_buff) { + if(solid_) { + glClearStencil(0x0); + glClear(GL_STENCIL_BUFFER_BIT); + glEnable(GL_STENCIL_TEST); + glStencilFunc(GL_ALWAYS,0x0,0x1); + glStencilOp(GL_KEEP,GL_INVERT,GL_INVERT); + } + if(use_buff && !Scene::Instance().InOffscreenMode()) { #if OST_SHADER_SUPPORT_ENABLED #if 0 @@ -1230,8 +1241,35 @@ void IndexedVertexArray::draw_ltq(bool use_buff) glDrawElements(GL_LINES,line_index_list_.size(),GL_UNSIGNED_INT,&line_index_list_[0]); } } + + if(solid_) { + glStencilFunc(GL_EQUAL,0x1,0x1); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + + float fov=Scene::Instance().GetFOV()*M_PI/180.0; + float znear=Scene::Instance().GetNear(); + float aspect=Scene::Instance().GetAspect(); + float rh=2.0*fabs(tan(fov)*znear); + float rw=rh*aspect; + float rz=-znear-0.1; + + glDisable(GL_LIGHTING); + + glBegin(GL_TRIANGLE_STRIP); + glColor3fv(solid_color_); + glNormal3f(0,0,1); + glVertex3f(-rw,-rh,rz); + glVertex3f(rw,-rh,rz); + glVertex3f(-rw,rh,rz); + glVertex3f(rw,rh,rz); + glEnd(); + glDisable(GL_STENCIL_TEST); + glPopMatrix(); + } } - + void IndexedVertexArray::draw_p(bool use_buff) { if(use_buff && !Scene::Instance().InOffscreenMode()) { @@ -1254,115 +1292,115 @@ void IndexedVertexArray::draw_p(bool use_buff) namespace { -struct AALineEntry { - float p0[3], p1[3]; - float edge0[3],edge1[3],edge2[3],edge3[3]; - float c0[4], c1[4]; - float z; -}; + struct AALineEntry { + float p0[3], p1[3]; + float edge0[3],edge1[3],edge2[3],edge3[3]; + float c0[4], c1[4]; + float z; + }; -typedef std::vector<AALineEntry> AALineList; + typedef std::vector<AALineEntry> AALineList; -struct AALineEntryLess -{ - bool operator()(const AALineEntry& e1, const AALineEntry& e2) + struct AALineEntryLess { - return e1.z<e2.z; - } -}; + bool operator()(const AALineEntry& e1, const AALineEntry& e2) + { + return e1.z<e2.z; + } + }; -/* - Adapted after Chan and Durand, "Fast Prefiltered Lines", - in GPU Gems 2 -*/ -void render_aalines(AALineList& line_list, float w, float r) -{ + /* + Adapted after Chan and Durand, "Fast Prefiltered Lines", + in GPU Gems 2 + */ + void render_aalines(AALineList& line_list, float w, float r) + { #if OST_SHADER_SUPPORT_ENABLED - static GLuint table_tex_id=0; - std::vector<unsigned char> tex_table(32); + static GLuint table_tex_id=0; + std::vector<unsigned char> tex_table(32); - if(table_tex_id==0) { - for(int i=0;i<32;++i) { - float x=static_cast<float>(i)/31.0; - tex_table[31-i]=static_cast<unsigned char>(255.0*exp(-4.0*x*x)); + if(table_tex_id==0) { + for(int i=0;i<32;++i) { + float x=static_cast<float>(i)/31.0; + tex_table[31-i]=static_cast<unsigned char>(255.0*exp(-4.0*x*x)); + } + glGenTextures(1,&table_tex_id); + glBindTexture(GL_TEXTURE_1D,table_tex_id); + glPixelStorei(GL_UNPACK_ALIGNMENT,1); + glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexImage1D(GL_TEXTURE_1D,0,GL_LUMINANCE,32,0,GL_LUMINANCE,GL_UNSIGNED_BYTE,&tex_table[0]); } - glGenTextures(1,&table_tex_id); - glBindTexture(GL_TEXTURE_1D,table_tex_id); - glPixelStorei(GL_UNPACK_ALIGNMENT,1); - glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP); - glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexImage1D(GL_TEXTURE_1D,0,GL_LUMINANCE,32,0,GL_LUMINANCE,GL_UNSIGNED_BYTE,&tex_table[0]); - } - std::sort(line_list.begin(),line_list.end(),AALineEntryLess()); - - Shader::Instance().PushProgram(); - Shader::Instance().Activate("aaline"); + std::sort(line_list.begin(),line_list.end(),AALineEntryLess()); - glLineWidth(ceil((2.0f*r+w)*1.5)); + Shader::Instance().PushProgram(); + Shader::Instance().Activate("aaline"); - glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT); - glDisable(GL_NORMALIZE); - glDisable(GL_CULL_FACE); - glDisable(GL_LIGHTING); - glDisable(GL_COLOR_MATERIAL); - //glDisable(GL_DEPTH_TEST); - glDisable(GL_LINE_SMOOTH); - glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); - glEnable(GL_BLEND); - glDepthMask(0); - Shader::Instance().UpdateState(); - - GLuint cpr = Shader::Instance().GetCurrentProgram(); - GLint edge0_id = glGetUniformLocation(cpr,"edge0"); - GLint edge1_id = glGetUniformLocation(cpr,"edge1"); - GLint edge2_id = glGetUniformLocation(cpr,"edge2"); - GLint edge3_id = glGetUniformLocation(cpr,"edge3"); - GLint table_id = glGetUniformLocation(cpr,"table"); - - glActiveTexture(GL_TEXTURE0); - glDisable(GL_TEXTURE_2D); - glEnable(GL_TEXTURE_1D); - glBindTexture(GL_TEXTURE_1D,table_tex_id); - glUniform1i(table_id,0); - - for(AALineList::iterator it=line_list.begin(); - it!=line_list.end();++it) { - glUniform3fv(edge0_id,1,it->edge0); - glUniform3fv(edge1_id,1,it->edge1); - glUniform3fv(edge2_id,1,it->edge2); - glUniform3fv(edge3_id,1,it->edge3); - // glUniform cannot be inside a glBegin / glEnd - glBegin(GL_LINES); - glColor4fv(it->c0); - glVertex3fv(it->p0); - glColor4fv(it->c1); - glVertex3fv(it->p1); - glEnd(); - } + glLineWidth(ceil((2.0f*r+w)*1.5)); - glPopAttrib(); + glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT); + glDisable(GL_NORMALIZE); + glDisable(GL_CULL_FACE); + glDisable(GL_LIGHTING); + glDisable(GL_COLOR_MATERIAL); + //glDisable(GL_DEPTH_TEST); + glDisable(GL_LINE_SMOOTH); + glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + glDepthMask(0); + Shader::Instance().UpdateState(); + + GLuint cpr = Shader::Instance().GetCurrentProgram(); + GLint edge0_id = glGetUniformLocation(cpr,"edge0"); + GLint edge1_id = glGetUniformLocation(cpr,"edge1"); + GLint edge2_id = glGetUniformLocation(cpr,"edge2"); + GLint edge3_id = glGetUniformLocation(cpr,"edge3"); + GLint table_id = glGetUniformLocation(cpr,"table"); - Shader::Instance().PopProgram(); + glActiveTexture(GL_TEXTURE0); + glDisable(GL_TEXTURE_2D); + glEnable(GL_TEXTURE_1D); + glBindTexture(GL_TEXTURE_1D,table_tex_id); + glUniform1i(table_id,0); + + for(AALineList::iterator it=line_list.begin(); + it!=line_list.end();++it) { + glUniform3fv(edge0_id,1,it->edge0); + glUniform3fv(edge1_id,1,it->edge1); + glUniform3fv(edge2_id,1,it->edge2); + glUniform3fv(edge3_id,1,it->edge3); + // glUniform cannot be inside a glBegin / glEnd + glBegin(GL_LINES); + glColor4fv(it->c0); + glVertex3fv(it->p0); + glColor4fv(it->c1); + glVertex3fv(it->p1); + glEnd(); + } + + glPopAttrib(); + + Shader::Instance().PopProgram(); #endif -} + } -Vec3 make_aaline_edge(const Vec2& c1, const Vec2& c0, float s) -{ - Vec3 nrvo(c1[1]-c0[1],c0[0]-c1[0],c1[0]*c0[1]-c0[0]*c1[1]); - nrvo*=1.0/(s*Length(c1-c0)); - return nrvo; -} + Vec3 make_aaline_edge(const Vec2& c1, const Vec2& c0, float s) + { + Vec3 nrvo(c1[1]-c0[1],c0[0]-c1[0],c1[0]*c0[1]-c0[0]*c1[1]); + nrvo*=1.0/(s*Length(c1-c0)); + return nrvo; + } } - + void IndexedVertexArray::draw_aalines() { #if OST_SHADER_SUPPORT_ENABLED float w=0.5*line_width_; float r=w; float hwr = 0.5*w+r; - + AALineList line_list; for(unsigned int i=0;i<line_index_list_.size();i+=2) { Entry& ve0 = entry_list_[line_index_list_[i]]; @@ -1381,26 +1419,26 @@ void IndexedVertexArray::draw_aalines() Vec3 e1=make_aaline_edge(c1,c2,r); Vec3 e2=make_aaline_edge(c2,c3,r); Vec3 e3=make_aaline_edge(c3,c0,r); - + // TODO: it should be possible to avoid the unproject and // pass the projected coordinates directly to GL, setting // modelview and projection to unity; requires handling of // the viewport though! Vec3 np1=Scene::Instance().UnProject(q0-Vec3(hwr*d),false); Vec3 np2=Scene::Instance().UnProject(q1+Vec3(hwr*d),false); - + AALineEntry le={{np1[0],np1[1],np1[2]}, - {np2[0],np2[1],np2[2]}, - {e0[0],e0[1],e0[2]}, - {e1[0],e1[1],e1[2]}, - {e2[0],e2[1],e2[2]}, - {e3[0],e3[1],e3[2]}, - {ve0.c[0],ve0.c[1],ve0.c[2],ve0.c[3]}, - {ve1.c[0],ve1.c[1],ve1.c[2],ve1.c[3]}, - -0.5*(q0[2]+q1[2])}; + {np2[0],np2[1],np2[2]}, + {e0[0],e0[1],e0[2]}, + {e1[0],e1[1],e1[2]}, + {e2[0],e2[1],e2[2]}, + {e3[0],e3[1],e3[2]}, + {ve0.c[0],ve0.c[1],ve0.c[2],ve0.c[3]}, + {ve1.c[0],ve1.c[1],ve1.c[2],ve1.c[3]}, + -0.5*(q0[2]+q1[2])}; line_list.push_back(le); } - + render_aalines(line_list,w,r); #endif } @@ -1434,11 +1472,11 @@ geom::AlignedCuboid IndexedVertexArray::GetBoundingBox() const return geom::AlignedCuboid(geom::Vec3(0,0,0),geom::Vec3(0,0,0)); } else { geom::Vec3 minc(std::numeric_limits<float>::max(), - std::numeric_limits<float>::max(), - std::numeric_limits<float>::max()); + std::numeric_limits<float>::max(), + std::numeric_limits<float>::max()); geom::Vec3 maxc(-std::numeric_limits<float>::max(), - -std::numeric_limits<float>::max(), - -std::numeric_limits<float>::max()); + -std::numeric_limits<float>::max(), + -std::numeric_limits<float>::max()); for(EntryList::const_iterator it=entry_list_.begin();it!=entry_list_.end();++it) { geom::Vec3 p(it->v[0],it->v[1],it->v[2]); minc=geom::Min(minc,p); diff --git a/modules/gfx/src/vertex_array.hh b/modules/gfx/src/vertex_array.hh index ee63c939aae475959cfa12963b730f7326392df6..539d871b775c6219a397c0ca4795a23baa8c402b 100644 --- a/modules/gfx/src/vertex_array.hh +++ b/modules/gfx/src/vertex_array.hh @@ -117,6 +117,11 @@ class DLLEXPORT_OST_GFX IndexedVertexArray { void SetOutlineExpandColor(const Color& c); Color GetOutlineExpandColor() const {return outline_exp_color_;} + void SetSolid(bool f) {solid_=f;} + bool GetSolid() const {return solid_;} + void SetSolidColor(const Color& c) {solid_color_=c;} + bool GetSolidcolor() const {return solid_color_;} + // vertex, normal, color and texcoord (T2F_C4F_N3F_V3F) VertexID Add(const geom::Vec3& vert, const geom::Vec3& norm, const Color& col, const geom::Vec2& tex=geom::Vec2()); @@ -233,7 +238,8 @@ class DLLEXPORT_OST_GFX IndexedVertexArray { unsigned int outline_mat_dlist_; float outline_exp_factor_; Color outline_exp_color_; - + bool solid_; + Color solid_color_; bool draw_normals_; bool use_tex_; diff --git a/modules/gui/pymod/init_spacenav.py b/modules/gui/pymod/init_spacenav.py index c05a59a2dbee5d372870ec12db1090bb485c5e46..f94b569f97d8c943fc2fd2ee5f369fd5c976961e 100644 --- a/modules/gui/pymod/init_spacenav.py +++ b/modules/gui/pymod/init_spacenav.py @@ -46,10 +46,11 @@ class SpacenavControl(QtCore.QObject): def Toggle(self, button): if button == 0: self.trans = not self.trans - ost.LogVerbose("SpaceNav: translation %s "%("enabled" if self.trans else "disabled")) + ost.LogVerbose("SpaceNav: translation %s" % (self.strans and "enabled" or "disabled")) elif button == 1: self.rot = not self.rot - ost.LogVerbose("SpaceNav: rotation %s"%("enabled" if self.rot else "disabled")) + #ost.LogVerbose("SpaceNav: rotation %s"%("enabled" if self.rot else "disabled")) + ost.LogVerbose("SpaceNav: rotation %s"%(self.rot and "enabled" or "disabled")) elif button == 12: if self.speed > 20: self.speed *= 0.8 diff --git a/modules/gui/src/gosty.cc b/modules/gui/src/gosty.cc index 670c454c1886f0c1c2013954d3996a38060781b6..a0be0fae0762c45d1ae9596cdf57f65c168d8d5a 100644 --- a/modules/gui/src/gosty.cc +++ b/modules/gui/src/gosty.cc @@ -117,7 +117,7 @@ void setup_python_search_path(const String& root, PythonInterpreter& pi) # if (defined(__ppc64__) || defined(__x86_64__)) && !defined(__APPLE__) pi.AppendModulePath(QString::fromStdString(root+"/lib64/"+ site_pkgs.str()+ - "site-packages")); + "/site-packages")); # else pi.AppendModulePath(QString::fromStdString(root+"/lib/"+ site_pkgs.str()+ @@ -200,6 +200,23 @@ void prepare_scripts(int argc, char** argv, PythonInterpreter& py) py.RunScript(argv[1]); } +class MyApplication : public QApplication +{ +public: + MyApplication(int argc, char** argv) : QApplication(argc, argv) {} + virtual ~MyApplication() {} + virtual bool notify(QObject *rec, QEvent *ev) + { + try { + return QApplication::notify(rec, ev); + } catch( std::runtime_error& e) { + std::cerr << "runtime_error in Qt main loop: " << e.what() << std::endl; + exit(0); + } + return false; + } +}; + } @@ -208,7 +225,7 @@ int main(int argc, char** argv) { int dummy_argc=1; - QApplication app(dummy_argc,argv); + MyApplication app(dummy_argc,argv); QCoreApplication::setOrganizationName("OpenStructure"); QCoreApplication::setOrganizationDomain("openstructure.org"); QCoreApplication::setApplicationName(QString(argv[2])); diff --git a/modules/gui/src/sequence_viewer/sequence_model.cc b/modules/gui/src/sequence_viewer/sequence_model.cc index 0a98033c703cef68d0cd0c49fee8b8dd85f065c2..d64020ad925ca9307ca3fafd423f7de027d4684c 100644 --- a/modules/gui/src/sequence_viewer/sequence_model.cc +++ b/modules/gui/src/sequence_viewer/sequence_model.cc @@ -50,7 +50,8 @@ SequenceModel::SequenceModel(QObject *parent) this->endInsertRows(); } -void SequenceModel::InsertSequence(QString& name, seq::SequenceHandle& seq){ +void SequenceModel::InsertSequence(QString& name, seq::SequenceHandle& seq) +{ int cols = this->columnCount(); int new_cols = seq.GetLength(); this->beginInsertRows(QModelIndex(),this->rowCount(),this->rowCount()); @@ -63,7 +64,7 @@ void SequenceModel::InsertSequence(QString& name, seq::SequenceHandle& seq){ this->endInsertRows(); } -void SequenceModel::InsertChain(QString& name, mol::ChainView& view){ +void SequenceModel::InsertChain(QString& name, mol::ChainView& view) { int cols = this->columnCount(); int new_cols = view.GetResidueCount(); this->beginInsertRows(QModelIndex(),this->rowCount(),this->rowCount()); @@ -89,8 +90,10 @@ void SequenceModel::InsertAlignment(const seq::AlignmentHandle& alignment){ 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()); +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(); } @@ -143,7 +146,7 @@ void SequenceModel::RemoveAlignment(const seq::AlignmentHandle& alignment){ } } -int SequenceModel::GetColumnCount() const{ +int SequenceModel::GetColumnCount() const { int cols = 0; for(int i = 0; i<objects_.size();i++){ int ob_cols = objects_[i]->GetMaxColumnCount(); @@ -154,7 +157,8 @@ int SequenceModel::GetColumnCount() const{ return cols; } -SequenceViewObject* SequenceModel::GetItem(const gfx::EntityP& entity){ +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])){ @@ -167,7 +171,8 @@ SequenceViewObject* SequenceModel::GetItem(const gfx::EntityP& entity){ return NULL; } -AlignmentViewObject* SequenceModel::GetItem(const seq::AlignmentHandle& alignment){ +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()){ @@ -178,7 +183,8 @@ AlignmentViewObject* SequenceModel::GetItem(const seq::AlignmentHandle& alignmen return NULL; } -const PainterList& SequenceModel::GetPainters(const QModelIndex& index) const{ +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(); @@ -255,7 +261,8 @@ int SequenceModel::GetGlobalRow(BaseViewObject* obj, int row) const return glob_row; } -QModelIndexList SequenceModel::GetModelIndexes(gfx::EntityP& entity, const mol::EntityView& view) +QModelIndexList SequenceModel::GetModelIndexes(gfx::EntityP& entity, + const mol::EntityView& view) { QModelIndexList list; if(BaseViewObject* object = this->GetItem(entity)){ @@ -275,7 +282,8 @@ QModelIndexList SequenceModel::GetModelIndexes(gfx::EntityP& entity, const mol:: return list; } -QModelIndexList SequenceModel::GetModelIndexes(const QString& subject, const QString& sequence_name) +QModelIndexList SequenceModel::GetModelIndexes(const QString& subject, + const QString& sequence_name) { QModelIndexList list; for (int i = 0; i<objects_.size(); i++){ @@ -295,7 +303,8 @@ QModelIndexList SequenceModel::GetModelIndexes(const QString& subject, const QSt return list; } -void SequenceModel::SelectionChanged(const QItemSelection& sel, const QItemSelection& desel) +void SequenceModel::SelectionChanged(const QItemSelection& sel, + const QItemSelection& desel) { QMap<int,QPair<QSet<int>,QSet<int> > > sel_map; const QModelIndexList& sel_indexes = sel.indexes(); diff --git a/modules/gui/src/sequence_viewer/sequence_row.cc b/modules/gui/src/sequence_viewer/sequence_row.cc index 30199dd6f7c69c0653064f0259f5870590a60adf..1d431cbae8bc0998d00e0e3281429aaf8bbaacbf 100644 --- a/modules/gui/src/sequence_viewer/sequence_row.cc +++ b/modules/gui/src/sequence_viewer/sequence_row.cc @@ -34,13 +34,18 @@ #include <QtGui> namespace ost { namespace gui { -SequenceRow::SequenceRow(const QString& name, seq::ConstSequenceHandle sequence, SequenceViewObject* parent) : BaseRow(QFont("Courier",11),parent), name_(name), name_font_(QFont("Courier",11)), sequence_(sequence) +SequenceRow::SequenceRow(const QString& name, seq::ConstSequenceHandle 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, SequenceViewObject* parent) : BaseRow(QFont("Courier",11),parent), name_(name), name_font_(QFont("Courier",11)) +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); diff --git a/modules/gui/src/sequence_viewer/sequence_table_view.cc b/modules/gui/src/sequence_viewer/sequence_table_view.cc index 90b4baa5bc4ef8ce742a006ab5b38227409e059a..68eb7d2d8766a8204987f7aae0e641e1980cd9f3 100644 --- a/modules/gui/src/sequence_viewer/sequence_table_view.cc +++ b/modules/gui/src/sequence_viewer/sequence_table_view.cc @@ -60,8 +60,10 @@ SequenceTableView::SequenceTableView(QAbstractItemModel * model) this->setHorizontalScrollMode(ScrollPerPixel); this->setVerticalScrollMode(ScrollPerPixel); - connect(this->horizontalHeader(),SIGNAL(sectionResized(int,int,int)), this, SLOT(ResizeWidth(int,int,int))); - connect(this->verticalHeader(),SIGNAL(sectionResized(int,int,int)), this, SLOT(ResizeHeight(int,int,int))); + connect(this->horizontalHeader(),SIGNAL(sectionResized(int,int,int)), + this, SLOT(ResizeWidth(int,int,int))); + connect(this->verticalHeader(),SIGNAL(sectionResized(int,int,int)), + this, SLOT(ResizeHeight(int,int,int))); delegate_ = new SequenceDelegate(qobject_cast<SequenceModel*>(this->model()),this); @@ -140,8 +142,10 @@ void SequenceTableView::InitStaticRow() static_row_->setItemDelegate(delegate_); - connect(static_row_->horizontalScrollBar(), SIGNAL(valueChanged(int)), this->horizontalScrollBar(), SLOT(setValue(int))); - connect(horizontalScrollBar(), SIGNAL(valueChanged(int)), static_row_->horizontalScrollBar(), SLOT(setValue(int))); + connect(static_row_->horizontalScrollBar(), SIGNAL(valueChanged(int)), + this->horizontalScrollBar(), SLOT(setValue(int))); + connect(horizontalScrollBar(), SIGNAL(valueChanged(int)), + static_row_->horizontalScrollBar(), SLOT(setValue(int))); this->updateStaticRow(); } @@ -179,10 +183,14 @@ void SequenceTableView::InitStaticField(){ static_field_->setHorizontalScrollMode(ScrollPerPixel); static_field_->setVerticalScrollMode(ScrollPerPixel); - connect(static_field_->horizontalScrollBar(), SIGNAL(valueChanged(int)), this->horizontalScrollBar(), SLOT(setValue(int))); - connect(horizontalScrollBar(), SIGNAL(valueChanged(int)), static_field_->horizontalScrollBar(), SLOT(setValue(int))); - connect(static_field_->verticalScrollBar(), SIGNAL(valueChanged(int)), this->verticalScrollBar(), SLOT(setValue(int))); - connect(verticalScrollBar(), SIGNAL(valueChanged(int)), static_field_->verticalScrollBar(), SLOT(setValue(int))); + connect(static_field_->horizontalScrollBar(), SIGNAL(valueChanged(int)), + this->horizontalScrollBar(), SLOT(setValue(int))); + connect(horizontalScrollBar(), SIGNAL(valueChanged(int)), + static_field_->horizontalScrollBar(), SLOT(setValue(int))); + connect(static_field_->verticalScrollBar(), SIGNAL(valueChanged(int)), + this->verticalScrollBar(), SLOT(setValue(int))); + connect(verticalScrollBar(), SIGNAL(valueChanged(int)), + static_field_->verticalScrollBar(), SLOT(setValue(int))); this->updateStaticField(); } @@ -222,7 +230,8 @@ void SequenceTableView::resizeEvent(QResizeEvent * event) #endif } -QModelIndex SequenceTableView::moveCursor(CursorAction action, Qt::KeyboardModifiers modifiers) +QModelIndex SequenceTableView::moveCursor(CursorAction action, + Qt::KeyboardModifiers modifiers) { QModelIndex current = QTableView::moveCursor(action, modifiers); diff --git a/modules/gui/src/sequence_viewer/sequence_viewer.cc b/modules/gui/src/sequence_viewer/sequence_viewer.cc index a34e917b6c20e86e2ba752c08d3b5e2ced3a2c29..29314805cad9465325bad4281f8e670a3e8bb2ad 100644 --- a/modules/gui/src/sequence_viewer/sequence_viewer.cc +++ b/modules/gui/src/sequence_viewer/sequence_viewer.cc @@ -132,7 +132,8 @@ void SequenceViewer::InitSearchBar() 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&))); + connect(seq_search_bar_, SIGNAL(Changed(const QString&, bool, const QString&)), + this, SLOT(OnSearchBarUpdate(const QString&, bool, const QString&))); } void SequenceViewer::InitView() diff --git a/modules/gui/src/sequence_viewer/tick_painter.cc b/modules/gui/src/sequence_viewer/tick_painter.cc index eee4143d692c2e38ebc1a925543307fc3ec59dff..4c1558a5a5c02469670cddeaf8c31e77aa67d2ba 100644 --- a/modules/gui/src/sequence_viewer/tick_painter.cc +++ b/modules/gui/src/sequence_viewer/tick_painter.cc @@ -32,7 +32,8 @@ TickPainter::TickPainter(QObject* parent) : Painter(parent), pen_(QPen(Qt::darkGray)) {} -void TickPainter::Paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index){ +void TickPainter::Paint(QPainter* painter, const QStyleOptionViewItem& option, + const QModelIndex& index){ painter->save(); painter->setPen(pen_); QVariant value = index.data(Qt::DisplayRole); diff --git a/modules/gui/src/sequence_viewer/title_row.cc b/modules/gui/src/sequence_viewer/title_row.cc index ba7aaf280a761b9a91c39f9d26dbf02013171974..d4dd16fa5757f5ea4f43e1d5a971f1802c4381e4 100644 --- a/modules/gui/src/sequence_viewer/title_row.cc +++ b/modules/gui/src/sequence_viewer/title_row.cc @@ -41,29 +41,30 @@ QVariant TitleRow::GetData(int column, int role) const if(column<0){ return QVariant(); } - else if(role==Qt::DisplayRole && column%10==9){ - return QVariant(QString::number(column+1)); - } - else if(role==Qt::DisplayRole && column%10==0){ - return QVariant(QString::number(column)); - } - else if (role==Qt::FontRole){ - if(column < 999){ - return QVariant(font_); - } - else{ + switch (role) { + case Qt::DisplayRole: + if (column % 10 == 9) { + return QVariant(QString::number(column+1)); + } + if (column % 10 == 0) { + return QVariant(QString::number(column)); + } + return QVariant(); + case Qt::FontRole: + if(column < 999){ + return QVariant(font_); + } return QVariant(small_font_); - } - } - else if (role==Qt::TextAlignmentRole){ - return QVariant(Qt::AlignHCenter|Qt::AlignBottom); - } - else if (role==Qt::SizeHintRole){ + case Qt::TextAlignmentRole: + return QVariant(Qt::AlignHCenter|Qt::AlignBottom); + case Qt::SizeHintRole: { QSize size = this->GetCellSize(); size.setHeight(10); return QVariant(size); + } + default: + return BaseRow::GetData(column, role); } - return BaseRow::GetData(column, role); } Qt::ItemFlags TitleRow::Flags(int column) const @@ -79,7 +80,8 @@ void TitleRow::DoubleClicked(int column) if(this->parent()){ 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)); + QItemSelection add = QItemSelection(model->index(1,column), + model->index(rows,column)); model->SelectionChanged(add,QItemSelection()); } } diff --git a/modules/img/base/src/image_state/image_state_algorithm.hh b/modules/img/base/src/image_state/image_state_algorithm.hh index b601345196af9c1daec20fc6ec486846aa2d015a..e5546583a2208bd600c66d73667783aa3acb8338 100644 --- a/modules/img/base/src/image_state/image_state_algorithm.hh +++ b/modules/img/base/src/image_state/image_state_algorithm.hh @@ -34,7 +34,7 @@ namespace ost { namespace img { namespace image_state { /* one-time definition of the constructor adapters, allowing - zero to 10 ctor parameters to be automagically used. There + zero to 12 ctor parameters to be automagically used. There is probably a recursive way to do this more elegantly... this version includes a call to a base class to allow a name @@ -52,14 +52,14 @@ namespace ost { namespace img { namespace image_state { template <class P0, \ class P1> \ CLASS (const P0& p0, \ - const P1& p1): \ + const P1& p1): \ FNC(p0,p1), BASE (FNC::GetAlgorithmName()) {} \ /* 3 params */ \ template <class P0, \ class P1, \ class P2> \ CLASS (const P0& p0, \ - const P1& p1, \ + const P1& p1, \ const P2& p2): \ FNC(p0,p1,p2), BASE (FNC::GetAlgorithmName()) {} \ /* 4 params */ \ @@ -68,7 +68,7 @@ namespace ost { namespace img { namespace image_state { class P2, \ class P3> \ CLASS (const P0& p0, \ - const P1& p1, \ + const P1& p1, \ const P2& p2, \ const P3& p3): \ FNC(p0,p1,p2,p3), BASE (FNC::GetAlgorithmName()) {} \ @@ -79,7 +79,7 @@ namespace ost { namespace img { namespace image_state { class P3, \ class P4> \ CLASS (const P0& p0, \ - const P1& p1, \ + const P1& p1, \ const P2& p2, \ const P3& p3, \ const P4& p4): \ @@ -92,7 +92,7 @@ namespace ost { namespace img { namespace image_state { class P4, \ class P5> \ CLASS (const P0& p0, \ - const P1& p1, \ + const P1& p1, \ const P2& p2, \ const P3& p3, \ const P4& p4, \ @@ -107,7 +107,7 @@ namespace ost { namespace img { namespace image_state { class P5, \ class P6> \ CLASS (const P0& p0, \ - const P1& p1, \ + const P1& p1, \ const P2& p2, \ const P3& p3, \ const P4& p4, \ @@ -124,7 +124,7 @@ namespace ost { namespace img { namespace image_state { class P6, \ class P7> \ CLASS (const P0& p0, \ - const P1& p1, \ + const P1& p1, \ const P2& p2, \ const P3& p3, \ const P4& p4, \ @@ -143,7 +143,7 @@ namespace ost { namespace img { namespace image_state { class P7, \ class P8> \ CLASS (const P0& p0, \ - const P1& p1, \ + const P1& p1, \ const P2& p2, \ const P3& p3, \ const P4& p4, \ @@ -164,7 +164,7 @@ namespace ost { namespace img { namespace image_state { class P8, \ class P9> \ CLASS (const P0& p0, \ - const P1& p1, \ + const P1& p1, \ const P2& p2, \ const P3& p3, \ const P4& p4, \ @@ -187,7 +187,7 @@ namespace ost { namespace img { namespace image_state { class P9, \ class PA> \ CLASS (const P0& p0, \ - const P1& p1, \ + const P1& p1, \ const P2& p2, \ const P3& p3, \ const P4& p4, \ @@ -212,7 +212,7 @@ namespace ost { namespace img { namespace image_state { class PA, \ class PB> \ CLASS (const P0& p0, \ - const P1& p1, \ + const P1& p1, \ const P2& p2, \ const P3& p3, \ const P4& p4, \ @@ -221,8 +221,8 @@ namespace ost { namespace img { namespace image_state { const P7& p7, \ const P8& p8, \ const P9& p9, \ - const P9& pa, \ - const PA& pb): \ + const PA& pa, \ + const PB& pb): \ FNC(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,pa,pb), BASE (FNC::GetAlgorithmName()) {} @@ -356,8 +356,8 @@ private: */ template <class FNC> class TEMPLATE_EXPORT ImageStateConstModIPAlgorithm: public FNC, - public ConstModIPAlgorithm, - public ImageStateConstModIPVisitorBase { + public ConstModIPAlgorithm, + public ImageStateConstModIPVisitorBase { public: IMAGE_STATE_VISITOR_CTOR_ADAPTERS(ImageStateConstModIPAlgorithm, ConstModIPAlgorithm) @@ -409,8 +409,8 @@ private: //! out-of-place modifying image state const visitor plus op algorithm template <class FNC> class TEMPLATE_EXPORT ImageStateConstModOPAlgorithm: public FNC, - public ConstModOPAlgorithm, - public ImageStateConstModOPVisitorBase { + public ConstModOPAlgorithm, + public ImageStateConstModOPVisitorBase { public: IMAGE_STATE_VISITOR_CTOR_ADAPTERS(ImageStateConstModOPAlgorithm, ConstModOPAlgorithm) diff --git a/modules/io/pymod/__init__.py b/modules/io/pymod/__init__.py index 6df260a86ccd23e4a9b2b77094cef6ae85379c6d..616f04c087feb24b1347353f69f161464b0ea194 100644 --- a/modules/io/pymod/__init__.py +++ b/modules/io/pymod/__init__.py @@ -388,19 +388,19 @@ def _PDBize(biounit, asu, seqres=None, min_polymer_size=10): tr = geom.Mat4() tr = trans * rot trans_matrices.append(tr) - for op_n in range(1, len(operations)): - tmp_ops = list() - for o in operations[op_n]: - rot = geom.Mat4() - rot.PasteRotation(o.rotation) - trans = geom.Mat4() - trans.PasteTranslation(o.translation) - tr = geom.Mat4() - tr = trans * rot - for t_o in trans_matrices: - tp = t_o * tr - tmp_ops.append(tp) - trans_matrices = tmp_ops + for op_n in range(1, len(operations)): + tmp_ops = list() + for o in operations[op_n]: + rot = geom.Mat4() + rot.PasteRotation(o.rotation) + trans = geom.Mat4() + trans.PasteTranslation(o.translation) + tr = geom.Mat4() + tr = trans * rot + for t_o in trans_matrices: + tp = t_o * tr + tmp_ops.append(tp) + trans_matrices = tmp_ops # select chains into a view as basis for each transformation assu = asu.Select('cname=' + ','.join(biounit.GetChainList())) # use each transformation on the view, store as entity and transform, PDBize @@ -426,6 +426,9 @@ def _PDBize(biounit, asu, seqres=None, min_polymer_size=10): edi.SetChainDescription(new_chain, chain.description) edi.SetChainType(new_chain, chain.type) new_chain.SetStringProp('original_name', chain.name) + if chain.HasProp("pdb_auth_chain_name"): + new_chain.SetStringProp("pdb_auth_chain_name", + chain.GetStringProp("pdb_auth_chain_name")) for res in chain.residues: new_res = edi.AppendResidue(new_chain, res.name, res.number) _CopyAtoms(res, new_res, edi, tr) @@ -456,6 +459,10 @@ def _PDBize(biounit, asu, seqres=None, min_polymer_size=10): mol.ResNum(last_rnum+1, ins_code)) new_res.SetStringProp('description', chain.description) new_res.SetStringProp('type', mol.StringFromChainType(chain.type)) + new_res.SetStringProp("original_name", chain.name) + if chain.HasProp("pdb_auth_chain_name"): + new_res.SetStringProp("pdb_auth_chain_name", + chain.GetStringProp("pdb_auth_chain_name")) ins_code = chr(ord(ins_code)+1) _CopyAtoms(res, new_res, edi, tr) # FIXME: get rid of connect all call... diff --git a/modules/io/src/img/map_io_mrc_handler.cc b/modules/io/src/img/map_io_mrc_handler.cc index bdde9d1e1701bb7180874db98d9bf9f7f8dc47a1..55d4f69138c1e48b90d797f2c3aefe31b2b8efe2 100644 --- a/modules/io/src/img/map_io_mrc_handler.cc +++ b/modules/io/src/img/map_io_mrc_handler.cc @@ -585,13 +585,13 @@ void real_filler(img::image_state::RealSpatialImageState& isi, img::Progress::Instance().Register(&this_dummy,header.ns*header.nr,100); for(int is=0;is<header.ns;++is) { pnt[maps]=header.nsstart+is; + std::vector<B> buffer(header.nr*header.nc); + f.read(&buffer[0],header.nr*header.nc); for(int ir=0;ir<header.nr;++ir) { pnt[mapr]=header.nrstart+ir; for(int ic=0;ic<header.nc;++ic) { pnt[mapc]=header.ncstart+ic; - B tmp; - f >> tmp; - isi.Value(pnt) = static_cast<Real>(tmp); + isi.Value(pnt) = img::Val2Val<B,Real>(buffer[header.nc*ir+ic]); } img::Progress::Instance().AdvanceProgress(&this_dummy); } diff --git a/modules/io/src/img/map_io_png_handler.cc b/modules/io/src/img/map_io_png_handler.cc index 571cecfa907547716b6997e9397dccb04313b4bd..d77db114b4d20c72d026d10e3f6e2435a8737b06 100644 --- a/modules/io/src/img/map_io_png_handler.cc +++ b/modules/io/src/img/map_io_png_handler.cc @@ -226,12 +226,12 @@ void MapIOPngHandler::Export(const img::MapHandle& image, std::ostream& f,const info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { - png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); + png_destroy_write_struct(&png_ptr, (png_infopp)NULL); throw IOException("png: error creating info_struct"); } if (setjmp(png_jmpbuf(png_ptr))) { - png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); + png_destroy_write_struct(&png_ptr, &info_ptr); throw IOException("png: error setting jmpbuf"); } @@ -293,7 +293,7 @@ void MapIOPngHandler::Export(const img::MapHandle& image, std::ostream& f,const png_write_end(png_ptr, info_ptr); - png_destroy_write_struct(&png_ptr, (png_infopp)NULL); + png_destroy_write_struct(&png_ptr, &info_ptr); } diff --git a/modules/io/src/img/map_io_spi_handler.cc b/modules/io/src/img/map_io_spi_handler.cc index 6f5e1798b4674ed037884719036eeeda30323f6e..ad261daf908ec2bc0294f9b52e56a0d345d8553f 100644 --- a/modules/io/src/img/map_io_spi_handler.cc +++ b/modules/io/src/img/map_io_spi_handler.cc @@ -106,7 +106,7 @@ public: } } - float fNslice; // nr of slices (1 for an image, negative nr of slices for new long label format + float fNslice; // nr of slices (1 for an image, negative nr of slices indicates very old 2d image float fNrow; // nr row per slice (Y) float fNrec; // total nr of records (unused). float fNlabel; // obsolete, unused @@ -255,6 +255,9 @@ void header_filler(std::istream& in, spider_header& header) { BinaryIStream<CONVERSIONTYPE> f(in); f >> header.fNslice; + if(header.fNslice<1.0){ + header.fNslice=1.0; // fix for very old 2d images with Nslice=-1 + } f >> header.fNrow; f >> header.fNrec; f >> header.fNlabel; @@ -387,9 +390,8 @@ template <typename B > void real_dumper(std::ostream& f, const spider_header& header, const img::ImageHandle& mh,const img::alg::Normalizer& norm, bool swap_flag) { int padding = header.fLabbyt-f.tellp(); - char* buffer=new char[padding]; - f.write(buffer,padding); - delete[] buffer; + std::vector<char> buffer(padding,0); + f.write(&buffer[0],padding); int slice_size=static_cast<int>(header.fNcol) * static_cast<int>(header.fNrow); boost::scoped_array<B> rawp(new B[slice_size]); diff --git a/modules/io/src/img/map_io_tiff_handler.cc b/modules/io/src/img/map_io_tiff_handler.cc index 0f418bc896c6f0563a5a3a0d38d1e5aecfe6495e..e6144315b78e3c2c13ddd7669f68ca841b983d0d 100644 --- a/modules/io/src/img/map_io_tiff_handler.cc +++ b/modules/io/src/img/map_io_tiff_handler.cc @@ -51,7 +51,8 @@ String TIF::FORMAT_STRING="defined_tiff"; normalize_on_save_(normalize_on_save), bit_depth_(bit_depth), signed_(sign), - phasecolor_(phasecolor) + phasecolor_(phasecolor), + subimage_(subimage) { } @@ -60,7 +61,8 @@ TIF::TIF(String format_string, boost::logic::tribool normalize_on_save, Format normalize_on_save_(normalize_on_save), bit_depth_(bit_depth), signed_(sign), - phasecolor_(phasecolor) + phasecolor_(phasecolor), + subimage_(subimage) { } diff --git a/modules/io/src/mol/entity_io_crd_handler.cc b/modules/io/src/mol/entity_io_crd_handler.cc index 7820aba23f6715da589a4987475e0f5f9601e75c..d16358cc8029dd6b9dad17cf5e7beb039d159dd3 100644 --- a/modules/io/src/mol/entity_io_crd_handler.cc +++ b/modules/io/src/mol/entity_io_crd_handler.cc @@ -33,6 +33,7 @@ #include <ost/conop/conop.hh> #include <ost/mol/xcs_editor.hh> #include <ost/profile.hh> +#include <ost/boost_filesystem_helper.hh> #include <ost/io/io_exception.hh> #include <ost/io/mol/io_profile.hh> @@ -245,11 +246,7 @@ CRDWriter::CRDWriter(std::ostream& ostream, bool ext) : {} CRDWriter::CRDWriter(const boost::filesystem::path& filename, bool ext) : -#if BOOST_FILESYSTEM_VERSION==3 || BOOST_VERSION<103400 - outfile_(filename.string().c_str()), -#else - outfile_(filename.file_string().c_str()), -#endif + outfile_(BFPathToString(filename).c_str()), outstream_(outfile_), ext_(ext), atom_count_(0), res_count_(0) {} diff --git a/modules/io/src/mol/entity_io_mae_handler.cc b/modules/io/src/mol/entity_io_mae_handler.cc index b21407458c4422f105834152444f91215f6e2060..3c68d9964323a2b37df8636320d797f88fb93751 100644 --- a/modules/io/src/mol/entity_io_mae_handler.cc +++ b/modules/io/src/mol/entity_io_mae_handler.cc @@ -296,7 +296,23 @@ void MAEReader::parse_and_add_atom(mol::EntityHandle ent, if(update_residue) { if (!(curr_residue_=curr_chain_.FindResidue(rnum))) { - curr_residue_=editor.AppendResidue(curr_chain_, rkey, rnum); + if(curr_chain_.GetResidueCount()>0) { + int loc=curr_chain_.GetResidueCount()-1; + for(;loc>=0;--loc) { + if(curr_chain_.GetResidueByIndex(loc).GetNumber()<rnum) break; + } + if(loc<0) { + curr_residue_=editor.InsertResidueBefore(curr_chain_,0,rnum,rkey); + } else { + curr_residue_=editor.InsertResidueAfter(curr_chain_,loc,rnum,rkey); + } + if(!curr_residue_) { + // this should not happen... + curr_residue_=editor.AppendResidue(curr_chain_, rkey, rnum); + } + } else { + curr_residue_=editor.AppendResidue(curr_chain_, rkey, rnum); + } assert(curr_residue_.IsValid()); LOG_TRACE(" new residue " << curr_residue_); ++residue_count_; diff --git a/modules/io/src/mol/pdb_reader.cc b/modules/io/src/mol/pdb_reader.cc index 739bf6bd34e5363447409c26c0822f09b594403a..13638576106be52ab3e75ac8c640b0f3a18ad3a3 100644 --- a/modules/io/src/mol/pdb_reader.cc +++ b/modules/io/src/mol/pdb_reader.cc @@ -41,23 +41,23 @@ using boost::format; namespace { -bool IEquals(const StringRef& a, const StringRef& b) -{ - if (a.size()!=b.size()) { - return false; - } - for (size_t i=0; i<a.size(); ++i) { - if (toupper(a[i])!=b[i]) { + bool IEquals(const StringRef& a, const StringRef& b) + { + if (a.size()!=b.size()) { return false; } + for (size_t i=0; i<a.size(); ++i) { + if (toupper(a[i])!=b[i]) { + return false; + } + } + return true; } - return true; -} -mol::ResNum to_res_num(int num, char ins_code) -{ - return mol::ResNum(num, ins_code==' ' ? '\0' : ins_code); -} + mol::ResNum to_res_num(int num, char ins_code) + { + return mol::ResNum(num, ins_code==' ' ? '\0' : ins_code); + } } @@ -775,8 +775,25 @@ void PDBReader::ParseAndAddAtom(const StringRef& line, int line_num, curr_residue_=curr_chain_.FindResidue(res_num); } if (!curr_residue_.IsValid()) { - LOG_DEBUG("new residue " << res_name << " " << res_num); - curr_residue_=editor.AppendResidue(curr_chain_, res_name.str(), res_num); + if(curr_chain_.GetResidueCount()>0 && profile_.join_spread_atom_records) { + int loc=curr_chain_.GetResidueCount()-1; + for(;loc>=0;--loc) { + if(curr_chain_.GetResidueByIndex(loc).GetNumber()<res_num) break; + } + if(loc<0) { + curr_residue_=editor.InsertResidueBefore(curr_chain_,0,res_num,res_name.str()); + } else { + curr_residue_=editor.InsertResidueAfter(curr_chain_,loc,res_num,res_name.str()); + } + if(!curr_residue_) { + // this should not happen... + curr_residue_=editor.AppendResidue(curr_chain_, res_name.str(), res_num); + } + LOG_DEBUG("inserted new residue " << res_name << " " << res_num << " after " << loc); + } else { + curr_residue_=editor.AppendResidue(curr_chain_, res_name.str(), res_num); + LOG_DEBUG("appended new residue " << res_name << " " << res_num); + } warned_name_mismatch_=false; ++residue_count_; } diff --git a/modules/io/src/mol/pdb_writer.cc b/modules/io/src/mol/pdb_writer.cc index d06a5228c5890f593c40c86ac9ceb4617f6ee379..3df6a4917db7901bbc4cb246d8346cd3f7c25f19 100644 --- a/modules/io/src/mol/pdb_writer.cc +++ b/modules/io/src/mol/pdb_writer.cc @@ -28,6 +28,8 @@ #include <boost/filesystem/convenience.hpp> #include <boost/algorithm/string.hpp> +#include <ost/base.hh> +#include <ost/boost_filesystem_helper.hh> #include <ost/io/io_exception.hh> #include <ost/mol/atom_handle.hh> #include <ost/mol/residue_handle.hh> @@ -154,8 +156,10 @@ void write_atom(std::ostream& ostr, FormattedLine& line, } else { for (std::vector<String>::const_iterator i=names.begin(), e=names.end(); i!=e; ++i) { - geom::Mat4 tf=atom.GetEntity().GetTransformationMatrix(); - p=geom::Vec3(tf*geom::Vec4(atom.GetAltPos(*i))); + // GetAltPos always return orig pos, i.e. does not honor + // transformations like GetPos does - so apply it here + // seems like a FIXME... + p=atom.GetEntity().GetTransform().Apply(atom.GetAltPos(*i)); line(30, 50).Clear(); if (i->size()>1) { @@ -347,11 +351,7 @@ PDBWriter::PDBWriter(std::ostream& stream, const IOProfile& profile): PDBWriter::PDBWriter(const boost::filesystem::path& filename, const IOProfile& profile): -#if BOOST_FILESYSTEM_VERSION==3 || BOOST_VERSION<103400 - outfile_(filename.string().c_str()), outstream_(outfile_), -#else - outfile_(filename.file_string().c_str()), outstream_(outfile_), -#endif + outfile_(BFPathToString(filename).c_str()), outstream_(outfile_), mol_count_(0), line_(80), multi_model_(false), charmm_style_(profile.dialect=="CHARMM"), is_pqr_(false), profile_(profile), filename_("") diff --git a/modules/io/src/mol/sdf_writer.cc b/modules/io/src/mol/sdf_writer.cc index 973224e48aff879b099aacd5fbd0f85002071b1b..45bc1867a1d6083601189c2c149ff75c9eaebf64 100644 --- a/modules/io/src/mol/sdf_writer.cc +++ b/modules/io/src/mol/sdf_writer.cc @@ -22,6 +22,7 @@ #include "sdf_writer.hh" +#include <ost/boost_filesystem_helper.hh> #include <ost/mol/atom_view.hh> #include <ost/mol/residue_view.hh> #include <ost/mol/chain_view.hh> @@ -140,11 +141,7 @@ SDFWriter::SDFWriter(const String& filename) } SDFWriter::SDFWriter(const boost::filesystem::path& filename): -#if BOOST_FILESYSTEM_VERSION==3 || BOOST_VERSION<103400 - outfile_(filename.string().c_str()), -#else - outfile_(filename.file_string().c_str()), -#endif + outfile_(BFPathToString(filename).c_str()), ostr_(outfile_), counter_(0), atom_indices_() {} void SDFWriter::Write(const mol::EntityView& ent) { diff --git a/modules/io/tests/test_io_pdb.cc b/modules/io/tests/test_io_pdb.cc index 561e91576b565d77dc6e9701bbc803f225167f56..09e0b44748e26d70659c5d43ceb7c32a92ed35be 100644 --- a/modules/io/tests/test_io_pdb.cc +++ b/modules/io/tests/test_io_pdb.cc @@ -852,7 +852,13 @@ BOOST_AUTO_TEST_CASE(res_name_mismatch_tolerant) BOOST_AUTO_TEST_CASE(seqres_import) { - SetPrefixPath(getenv("OST_ROOT")); + char * ost_root=getenv("OST_ROOT"); + if(!ost_root){ + std::cout << "WARNING: skipping SEQRES import unit test. " + << "Rule-based builder is required" << std::endl; + return; + } + SetPrefixPath(ost_root); String lib_path=GetSharedDataPath()+"/compounds.chemlib"; conop::CompoundLibPtr compound_lib=conop::CompoundLib::Load(lib_path); if (!compound_lib) { diff --git a/modules/io/tests/test_mmcif_reader.cc b/modules/io/tests/test_mmcif_reader.cc index b66b9edde259be5d00a70e27bea0d8e4c982edce..9ae371699a9dba2da8da18ae5bca795951def935 100644 --- a/modules/io/tests/test_mmcif_reader.cc +++ b/modules/io/tests/test_mmcif_reader.cc @@ -138,7 +138,13 @@ BOOST_AUTO_TEST_CASE(mmcif_trystoreidx) BOOST_AUTO_TEST_CASE(mmcif_convert_seqres) { - SetPrefixPath(getenv("OST_ROOT")); + char * ost_root=getenv("OST_ROOT"); + if(!ost_root){ + std::cout << "WARNING: skipping SEQRES import unit test. " + << "Rule-based builder is required" << std::endl; + return; + } + SetPrefixPath(ost_root); String lib_path=GetSharedDataPath()+"/compounds.chemlib"; conop::CompoundLibPtr compound_lib=conop::CompoundLib::Load(lib_path); if (!compound_lib) { @@ -395,7 +401,13 @@ BOOST_AUTO_TEST_CASE(mmcif_entity_tests) BOOST_AUTO_TEST_CASE(mmcif_entity_poly_tests) { - SetPrefixPath(getenv("OST_ROOT")); + char * ost_root=getenv("OST_ROOT"); + if(!ost_root){ + std::cout << "WARNING: skipping SEQRES import unit test. " + << "Rule-based builder is required" << std::endl; + return; + } + SetPrefixPath(ost_root); String lib_path=GetSharedDataPath()+"/compounds.chemlib"; conop::CompoundLibPtr compound_lib=conop::CompoundLib::Load(lib_path); if (!compound_lib) { diff --git a/modules/mol/alg/src/lddt.cc b/modules/mol/alg/src/lddt.cc index 75eec8005263a6854319a158d10be07648cee03b..321ae803e14f6b166813cd36b75e987dc40ebf20 100644 --- a/modules/mol/alg/src/lddt.cc +++ b/modules/mol/alg/src/lddt.cc @@ -23,6 +23,8 @@ #include <boost/program_options.hpp> #include <boost/filesystem/fstream.hpp> #include <boost/filesystem/convenience.hpp> +#include <ost/base.hh> +#include <ost/boost_filesystem_helper.hh> #include <ost/mol/alg/local_dist_diff_test.hh> #include <ost/mol/alg/filter_clashes.hh> #include <ost/io/mol/pdb_reader.hh> @@ -286,11 +288,7 @@ int main (int argc, char **argv) boost::filesystem::path pathstring(files[i]); - #if BOOST_FILESYSTEM_VERSION==3 || BOOST_VERSION<103400 - String filestring=pathstring.string(); - #else - String filestring=pathstring.file_string(); - #endif + String filestring=BFPathToString(pathstring); std::cout << "File: " << files[i] << std::endl; std::pair<int,int> cov = compute_coverage(v,glob_dist_list); std::cout << "Coverage: " << (float(cov.first)/float(cov.second)) << " (" << cov.first << " out of " << cov.second << " residues)" << std::endl; diff --git a/modules/mol/alg/src/local_dist_diff_test.cc b/modules/mol/alg/src/local_dist_diff_test.cc index 74c6278e2075882cf2a35d32b97d75b742ebb678..8f936411652c58d407fe70706f17c09e6d087a05 100644 --- a/modules/mol/alg/src/local_dist_diff_test.cc +++ b/modules/mol/alg/src/local_dist_diff_test.cc @@ -390,6 +390,9 @@ bool IsStandardResidue(String rn) GlobalRDMap CreateDistanceList(const EntityView& ref,Real max_dist) { GlobalRDMap dist_list; + if (!ref.GetChainCount()) { + return dist_list; + } ResidueViewList ref_residues=ref.GetChainList()[0].GetResidueList(); for (ResidueViewList::iterator i=ref_residues.begin(), e=ref_residues.end(); i!=e; ++i) { if (IsStandardResidue(i->GetName())) { diff --git a/modules/mol/base/pymod/__init__.py b/modules/mol/base/pymod/__init__.py index c51905578ce1f422598c5769f2717f69c4039e0f..512e4daf082ef7e17f8c019dc92021ff799b6ccc 100644 --- a/modules/mol/base/pymod/__init__.py +++ b/modules/mol/base/pymod/__init__.py @@ -20,17 +20,17 @@ from _ost_mol import * import ost.geom as _geom from ost.mol import alg -__transform_warning_flag=True def Transform(tf=None): from ost import LogWarning - if __transform_warning_flag: + if Transform.mol_transform_warning_flag: LogWarning("mol.Transform is deprecated, please use geom.Transform instead") - __transform_warning_flag=False + Transform.mol_transform_warning_flag=False if tf: return _geom.Transform(tf) else: return _geom.Transform() +Transform.mol_transform_warning_flag=True def MergeCoordGroups(*coord_groups): """ diff --git a/modules/mol/base/pymod/export_editors.cc b/modules/mol/base/pymod/export_editors.cc index e53a02d35ffc39d35e826c9f34938dfd2821c4a1..aae903f7d276721545a60af51cd1ed0dff227263 100644 --- a/modules/mol/base/pymod/export_editors.cc +++ b/modules/mol/base/pymod/export_editors.cc @@ -42,11 +42,33 @@ BondHandle (EditorBase::*connect_b)(const AtomHandle&, const AtomHandle&, BondHandle (EditorBase::*connect_d)(const AtomHandle&, const AtomHandle&, Real, Real, Real, unsigned char)=&EditorBase::Connect; + +ChainHandle (EditorBase::*insert_chain_a)(const String& chain_name)=&EditorBase::InsertChain; +ChainHandle (EditorBase::*insert_chain_b)(const String& chain_name, + ChainHandle chain, bool deep)=&EditorBase::InsertChain; ResidueHandle (EditorBase::*append_a)(ChainHandle ch, const ResidueKey&)=&EditorBase::AppendResidue; ResidueHandle (EditorBase::*append_b)(ChainHandle ch, const ResidueKey&, const ResNum&)=&EditorBase::AppendResidue; +ResidueHandle (EditorBase::*append_c)(ChainHandle ch, ResidueHandle residue, + bool deep)=&EditorBase::AppendResidue; + +AtomHandle (EditorBase::*insert_atom_a)(ResidueHandle residue, const String& name, + const geom::Vec3& pos, const String& ele, + Real occupancy, Real b_factor, + bool is_hetatm)=&EditorBase::InsertAtom; +AtomHandle (EditorBase::*insert_atom_b)(ResidueHandle residue, AtomHandle atom)=&EditorBase::InsertAtom; + + +AtomHandle (EditorBase::*insert_alt_atom_a)(ResidueHandle residue, const String& name, + const String& alt_group, const geom::Vec3& pos, + const String& ele, Real occ, + Real b_factor)=&EditorBase::InsertAltAtom; +AtomHandle (EditorBase::*insert_alt_atom_b)(ResidueHandle residue, AtomHandle atom, + const String& alt_group)=&EditorBase::InsertAltAtom; + + void (ICSEditor::*set_torsion_a)(TorsionHandle, Real, bool)=&ICSEditor::SetTorsionAngle; void (ICSEditor::*set_torsion_b)(const AtomHandle&, const AtomHandle&, @@ -194,19 +216,25 @@ void export_Editors() import_array(); #endif + class_<EditorBase>("EditorBase", no_init) - .def("InsertChain", &EditorBase::InsertChain) - .def("InsertAtom", &EditorBase::InsertAtom, + .def("InsertChain", insert_chain_a) + .def("InsertChain", insert_chain_b,(arg("chain_name"),arg("chain"), arg("deep")=false)) + .def("InsertAtom", insert_atom_a, (arg("residue"), arg("name"), arg("pos"), arg("element")="", arg("occupancy")=1.0, arg("b_factor")=0.0, arg("is_hetatm")=false)) - .def("InsertAltAtom", &EditorBase::InsertAltAtom) + .def("InsertAtom", insert_atom_b) + .def("InsertAltAtom", insert_alt_atom_a) + .def("InsertAltAtom", insert_alt_atom_b) .def("DeleteResidue", &EditorBase::DeleteResidue) .def("DeleteChain", &EditorBase::DeleteChain) .def("DeleteAtom", &EditorBase::DeleteAtom) .def("InsertResidueBefore", &EditorBase::InsertResidueBefore) - .def("InsertResidueAfter", &EditorBase::InsertResidueAfter) + .def("InsertResidueAfter", &EditorBase::InsertResidueAfter) .def("AppendResidue", append_a) - .def("AppendResidue", append_b) + .def("AppendResidue", append_b) + .def("AppendResidue", append_c, (arg("chain"), arg("residue"), + arg("deep")=false)) .def("Connect", connect_a) .def("Connect", connect_b) .def("Connect", connect_c) @@ -223,12 +251,19 @@ void export_Editors() .def("RenumberAllResidues",&EditorBase::RenumberAllResidues) ; + void (XCSEditor::*apply_transform1)(const geom::Mat4&) = &XCSEditor::ApplyTransform; + void (XCSEditor::*apply_transform2)(const geom::Transform&) = &XCSEditor::ApplyTransform; + void (XCSEditor::*set_transform1)(const geom::Mat4&) = &XCSEditor::SetTransform; + void (XCSEditor::*set_transform2)(const geom::Transform&) = &XCSEditor::SetTransform; + class_<XCSEditor, bases<EditorBase> >("XCSEditor", no_init) .def("SetAtomPos", set_t_pos) .def("SetAtomTransformedPos", set_t_pos) .def("SetAtomOriginalPos", set_o_pos) - .def("ApplyTransform", &XCSEditor::ApplyTransform) - .def("SetTransform", &XCSEditor::SetTransform) + .def("ApplyTransform", apply_transform1) + .def("ApplyTransform", apply_transform2) + .def("SetTransform", set_transform1) + .def("SetTransform", set_transform2) .def("UpdateICS", &XCSEditor::UpdateICS) .def("__exit__", &XCSEditor::UpdateICS) ; diff --git a/modules/mol/base/pymod/export_entity.cc b/modules/mol/base/pymod/export_entity.cc index adf2c83b7621420f1000aafa96439f90d34a203f..bb55d9bd68234616da9d4bf69d646adccf559d71 100644 --- a/modules/mol/base/pymod/export_entity.cc +++ b/modules/mol/base/pymod/export_entity.cc @@ -100,9 +100,18 @@ PyObject* get_pos1(EntityHandle& entity) return get_pos2(entity,true); } +#endif +geom::Mat4 depr_get_transformation_matrix(const EntityHandle& eh) +{ + return eh.GetTransformationMatrix(); +} + +bool depr_is_transformation_identity(const EntityHandle& eh) +{ + return eh.IsTransformationIdentity(); +} -#endif } // ns void export_Entity() @@ -181,17 +190,17 @@ void export_Entity() .add_property("bonds", &EntityHandle::GetBondList) .def("GetBounds", &EntityHandle::GetBounds) .add_property("bounds", &EntityHandle::GetBounds) - .def("GetTransformationMatrix", &EntityHandle::GetTransformationMatrix, - return_value_policy<copy_const_reference>()) - .add_property("transform", - make_function(&EntityHandle::GetTransformationMatrix, - return_value_policy<copy_const_reference>())) - + .def("GetTransformationMatrix", depr_get_transformation_matrix) + .def("IsTransformationIdentity",depr_is_transformation_identity) + .def("GetTransform",&EntityHandle::GetTransform) + .def("SetTransform",&EntityHandle::SetTransform) + .add_property("transform",&EntityHandle::GetTransform,&EntityHandle::SetTransform) + .def("HasTransform",&EntityHandle::HasTransform) + .def("ClearTransform",&EntityHandle::ClearTransform) .def("EditXCS", &EntityHandle::EditXCS, arg("mode")=UNBUFFERED_EDIT) .def("EditICS", &EntityHandle::EditICS, arg("mode")=UNBUFFERED_EDIT) .def("RequestXCSEditor", &depr_request_xcs_editor, arg("mode")=UNBUFFERED_EDIT) .def("RequestICSEditor", &depr_request_ics_editor, arg("mode")=UNBUFFERED_EDIT) - .def("IsTransformationIdentity",&EntityHandle::IsTransformationIdentity) .def(self==self) .def(self!=self) #if OST_NUMPY_SUPPORT_ENABLED diff --git a/modules/mol/base/src/editor_base.cc b/modules/mol/base/src/editor_base.cc index c358a020475c36fb90b44aa48464b21dabc64342..be1b3f6d18b4ca84ad603a9a29867de6b32065a6 100644 --- a/modules/mol/base/src/editor_base.cc +++ b/modules/mol/base/src/editor_base.cc @@ -40,6 +40,13 @@ ChainHandle EditorBase::InsertChain(const String& chain_name) return ent_.Impl()->InsertChain(chain_name); } +ChainHandle EditorBase::InsertChain(const String& chain_name, ChainHandle chain, bool deep) +{ + impl::ChainImplPtr inserted_chain=ent_.Impl()->InsertChain(chain.Impl(), deep); + inserted_chain->SetName(chain_name); + return inserted_chain; +} + ResidueHandle EditorBase::AppendResidue(ChainHandle chain, const ResidueKey& k) { CheckHandleValidity(chain); @@ -54,6 +61,12 @@ ResidueHandle EditorBase::AppendResidue(ChainHandle chain, const ResidueKey& k, return ResidueHandle(chain.Impl()->AppendResidue(k, num)); } +ResidueHandle EditorBase::AppendResidue(ChainHandle chain, ResidueHandle residue, bool deep) +{ + CheckHandleValidity(chain); + return ResidueHandle(chain.Impl()->AppendResidue(residue.Impl(), deep)); +} + ResidueHandle EditorBase::InsertResidueBefore(ChainHandle chain, int index, const ResNum& num, const ResidueKey& k) @@ -116,6 +129,14 @@ AtomHandle EditorBase::InsertAtom(ResidueHandle res, const String& name, return atom; } +AtomHandle EditorBase::InsertAtom(ResidueHandle res, AtomHandle atom) +{ + CheckHandleValidity(res); + ent_.Impl()->MarkTraceDirty(); + AtomHandle a(res.Impl()->InsertAtom(atom.Impl())); + return a; +} + AtomHandle EditorBase::InsertAltAtom(ResidueHandle res, const String& name, const String& alt_group, const geom::Vec3& pos, @@ -130,6 +151,18 @@ AtomHandle EditorBase::InsertAltAtom(ResidueHandle res, const String& name, return atom; } +AtomHandle EditorBase::InsertAltAtom(ResidueHandle res, AtomHandle atom, + const String& alt_group) +{ + CheckHandleValidity(res); + ent_.Impl()->MarkTraceDirty(); + AtomHandle a(res.Impl()->InsertAltAtom(atom.GetName(), alt_group, + atom.GetPos(), atom.GetElement(), + atom.GetOccupancy(), atom.GetBFactor())); + this->UpdateTrace(); + return a; +} + void EditorBase::AddAltAtomPos(const String& group, const AtomHandle& atom, const geom::Vec3& position, Real occ, diff --git a/modules/mol/base/src/editor_base.hh b/modules/mol/base/src/editor_base.hh index 576b3cdb7867bafb0191c642f8b891bc4af4d86b..d1674a68a9d2cde585b04e07c8ac2c5e6d58b1f8 100644 --- a/modules/mol/base/src/editor_base.hh +++ b/modules/mol/base/src/editor_base.hh @@ -57,6 +57,25 @@ public: /// \return The newly created chain handle ChainHandle InsertChain(const String& chain_name); + /// \brief create new chain + /// + /// create new chain with properties of a provided chain handle and attach it to entity. + /// + /// \param chain_name + /// The chain name. Can be an arbitrary String. However, if you + /// intend to use the PDB export funtionality, the \c chain_name + /// should be a single letter, preferably in the range A-Z. + /// \param chain + /// The newly created chain will take over all generic + /// attached to this handle. + /// \param deep + /// If set to true, all residues and atoms of chain will be + /// completely copied into the created chain. No bonds and angles + /// are added. + /// + /// \return The newly created chain handle + ChainHandle InsertChain(const String& chain_name, ChainHandle chain, bool deep=false); + /// \name Inserting, removing and modifying order of residues ///@{ /// \brief Append residue to the end of the chain @@ -76,6 +95,24 @@ public: ResidueHandle AppendResidue(ChainHandle chain, const ResidueKey& k, const ResNum& num); + + /// \brief Append residue to the ent of the chain + /// + /// Append residue with all properties of provided residue into chain. + /// + /// \param residue + /// All properties of this residue will be copied into the newly created + /// residue. The newly created residue will not contain any atoms, except + /// you set \var deep to true. + /// + /// \param deep + /// if set to true, all atoms from the source residue will be copied into + /// the newly created residue. No bonds and angles are added. + /// + /// \return The newly created residue handle + + ResidueHandle AppendResidue(ChainHandle chain, ResidueHandle residue, bool deep=false); + /// \brief Insert residue into chain /// /// Insert residue with residue number \var num and key \var k into the @@ -94,6 +131,7 @@ public: ResidueHandle InsertResidueBefore(ChainHandle chain, int index, const ResNum& num, const ResidueKey& k); + /// \brief insert residue into chain /// /// This method is identical to InsertResidueBefore() but inserts the @@ -120,12 +158,33 @@ public: Real occupancy=1.0, Real b_factor=0.0, bool is_hetatm=false); + /// \brief Insert new atom + /// + /// Inserts new atom with all properties from the provided atom handle. + /// + /// \param residue is the parent residue + /// \param atom from which all informations will be copied over to the + /// newly created atom + /// + /// \return the newly created AtomHandle + + AtomHandle InsertAtom(ResidueHandle residue, AtomHandle atom); + /// \brief Insert new atom with alternative position indicator /// \sa EditorBase::AddAltAtomPos(), ResidueHandle AtomHandle InsertAltAtom(ResidueHandle residue, const String& name, const String& alt_group, const geom::Vec3& pos, const String& ele="", Real occ=1.0, Real b_factor=0.0); + + /// \brief Insert new atom with alternative position indicator + /// + /// All informations will be copied over from atom, except bonds + + AtomHandle InsertAltAtom(ResidueHandle residue, AtomHandle atom, + const String& alt_group); + + /// \brief Add alternative atom position /// \param group is the name of the alternative atom position group. If no /// group of that name exists, it will be created. diff --git a/modules/mol/base/src/entity_handle.cc b/modules/mol/base/src/entity_handle.cc index 0abad5ede1b3241f05300b5768cf0b7c332f4c12..e34e11d2e233ab4a60da62e20c3e085c4ece1f58 100644 --- a/modules/mol/base/src/entity_handle.cc +++ b/modules/mol/base/src/entity_handle.cc @@ -17,6 +17,8 @@ // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA //------------------------------------------------------------------------------ +#include <ost/log.hh> + #include "impl/entity_impl.hh" #include "bond_handle.hh" #include "torsion_handle.hh" @@ -235,24 +237,62 @@ Real EntityHandle::GetAngle(const AtomView& a1, const AtomView& a2, return GetAngle(a1.GetHandle(), a2.GetHandle(), a3.GetHandle()); } -const geom::Mat4& EntityHandle::GetTransformationMatrix() const - +geom::Mat4 EntityHandle::GetTransformationMatrix() const { + static bool warn=true; + if(warn) { + LOG_WARNING("Entity::GetTransformationMatrix is deprecated, use GetTransform instead"); + warn=false; + } this->CheckValidity(); - return Impl()->GetTransfMatrix(); + return Impl()->GetTransform().GetMatrix(); } -const geom::Mat4& EntityHandle::GetInvTransformationMatrix() const +geom::Mat4 EntityHandle::GetInvTransformationMatrix() const { + static bool warn=true; + if(warn) { + LOG_WARNING("Entity::GetInvTransformationMatrix is deprecated, use GetTransform instead"); + warn=false; + } this->CheckValidity(); - return Impl()->GetInvTransfMatrix(); + return Impl()->GetTransform().GetInvertedMatrix(); } bool EntityHandle::IsTransformationIdentity() const +{ + static bool warn=true; + if(warn) { + LOG_WARNING("Entity::IsTransformationIdentity is deprecated, use HasTransform instead"); + warn=false; + } + this->CheckValidity(); + return !Impl()->HasTransform(); +} + +geom::Transform EntityHandle::GetTransform() const +{ + this->CheckValidity(); + return Impl()->GetTransform(); +} + +void EntityHandle::SetTransform(const geom::Transform& tf) +{ + this->CheckValidity(); + Impl()->SetTransform(tf); +} + +bool EntityHandle::HasTransform() const +{ + this->CheckValidity(); + return Impl()->HasTransform(); +} + +void EntityHandle::ClearTransform() { this->CheckValidity(); - return Impl()->IsTransfIdentity(); + Impl()->ClearTransform(); } ResidueHandle EntityHandle::FindResidue(const String& chain_name, diff --git a/modules/mol/base/src/entity_handle.hh b/modules/mol/base/src/entity_handle.hh index 2783b404b75b11a1e31127017d8461b740752cf5..fe2a439135306d6f2a7c080ed91f1e15604faea0 100644 --- a/modules/mol/base/src/entity_handle.hh +++ b/modules/mol/base/src/entity_handle.hh @@ -264,13 +264,22 @@ public: Real GetAngle(const AtomView& a1, const AtomView& a2, const AtomView& a3) const; - const geom::Mat4& GetTransformationMatrix() const; - - - const geom::Mat4& GetInvTransformationMatrix() const; - + /// \brief DEPRECATED + geom::Mat4 GetTransformationMatrix() const; + /// \brief DEPRECATED + geom::Mat4 GetInvTransformationMatrix() const; + /// \brief DEPRECATED bool IsTransformationIdentity() const; + /// \brief retrieve transformation of this entity + geom::Transform GetTransform() const; + /// \brief set transformation that will affect this entity + void SetTransform(const geom::Transform& t); + /// \brief checks whether a transform has been set + bool HasTransform() const; + /// \brief remove transform + void ClearTransform(); + /// \brief get complete list of residues /// \sa #ResiduesBegin, #ResiduesEnd ResidueHandleList GetResidueList() const; diff --git a/modules/mol/base/src/impl/atom_impl.cc b/modules/mol/base/src/impl/atom_impl.cc index 4f7f059b818eda692de6447a9b3d2b5d547037e7..3a2b4d013f2c14e82f345e55241aa911d0809ffe 100644 --- a/modules/mol/base/src/impl/atom_impl.cc +++ b/modules/mol/base/src/impl/atom_impl.cc @@ -56,10 +56,8 @@ AtomImpl::AtomImpl(const EntityImplPtr& e, state_(0), index_(index) { - EntityHandle ent = this->GetEntity(); - geom::Mat4 transf_matrix = ent.GetTransformationMatrix(); - geom::Vec3 transf_pos = geom::Vec3(transf_matrix*geom::Vec4(p)); - tf_pos_ = transf_pos; + EntityImplPtr eip = GetEntity(); + tf_pos_ = eip->HasTransform() ? eip->GetTransform().Apply(p) : p; prop_=AtomProp::GetDefaultProps(element_); } diff --git a/modules/mol/base/src/impl/chain_impl.cc b/modules/mol/base/src/impl/chain_impl.cc index 009f436a5406a42caeda27605574587d48decbe3..8b3cbe271eef0e860d78ea5039ac7f00a35e191e 100644 --- a/modules/mol/base/src/impl/chain_impl.cc +++ b/modules/mol/base/src/impl/chain_impl.cc @@ -61,7 +61,7 @@ bool ChainImpl::InSequence() const { return in_sequence_; } -ResidueImplPtr ChainImpl::AppendResidue(const ResidueImplPtr& res) +ResidueImplPtr ChainImpl::AppendResidue(const ResidueImplPtr& res, bool deep) { ResidueImplPtr dst_res=this->AppendResidue(res->GetKey(), res->GetNumber()); dst_res->Assign(*res.get()); @@ -70,6 +70,16 @@ ResidueImplPtr ChainImpl::AppendResidue(const ResidueImplPtr& res) dst_res->SetChemClass(res->GetChemClass()); dst_res->SetProtein(res->IsProtein()); dst_res->SetIsLigand(res->IsLigand()); + if(deep) + { + AtomImplList::iterator it=res->GetAtomList().begin(), + it_end=res->GetAtomList().end(); + for(;it!=it_end;++it) + { + AtomHandle atom=*it; + dst_res->InsertAtom(atom.Impl()); + } + } return dst_res; } @@ -520,5 +530,12 @@ void ChainImpl::SetInSequence(const int index) this->UpdateShifts(); } } + +void ChainImpl::UpdateTransformedPos() +{ + for (ResidueImplList::iterator rit=residue_list_.begin(); rit!=residue_list_.end(); ++rit) { + (*rit)->UpdateTransformedPos(); + } +} }}} // ns diff --git a/modules/mol/base/src/impl/chain_impl.hh b/modules/mol/base/src/impl/chain_impl.hh index bcb3436e2bc463dadcfe1ca6af4e1bbac48af24b..a2c607ec4e2df3cca3783a8a14532e795536593e 100644 --- a/modules/mol/base/src/impl/chain_impl.hh +++ b/modules/mol/base/src/impl/chain_impl.hh @@ -105,7 +105,9 @@ public: /// \brief append new residue with exactly the same parameters as res, but /// no atoms and bonds - ResidueImplPtr AppendResidue(const ResidueImplPtr& res); + // force deep to be set explicitely, because it is better than implicit + // (and since we are on the impl level interface consistency isn't that critical) + ResidueImplPtr AppendResidue(const ResidueImplPtr& res, bool deep); ResidueImplPtr InsertResidueBefore(int index, const ResNum& n, const ResidueKey& k); @@ -119,6 +121,7 @@ public: /// \brief Append residue at end of chain. ResidueImplPtr AppendResidue(const ResidueKey& k, const ResNum& n); + // next residue, not necessarily in sequence ResidueImplPtr GetPrev(const ResidueImplPtr& r) const; @@ -181,6 +184,8 @@ public: /// property and updates it accordingly void SetInSequence(int index); + void UpdateTransformedPos(); + private: int GetIndexForResNumInSequence(const ResNum& number) const; void UpdateShifts(); diff --git a/modules/mol/base/src/impl/entity_impl.cc b/modules/mol/base/src/impl/entity_impl.cc index 3019a0806e0dc3f8838157e09fcd69d93fb2888a..db9460a01cd68b16a91cdaa30f7e1dba3963591d 100644 --- a/modules/mol/base/src/impl/entity_impl.cc +++ b/modules/mol/base/src/impl/entity_impl.cc @@ -68,9 +68,8 @@ EntityImpl::EntityImpl(): chain_list_(), connector_map_(), torsion_map_(), - transformation_matrix_(), - inverse_transformation_matrix_(), - identity_transf_(true), + transform_(), + has_transform_(false), atom_organizer_(5.0), fragment_list_(), observer_map_(), @@ -127,10 +126,19 @@ EntityImplPtr EntityImpl::Copy() return ent_p; } -ChainImplPtr EntityImpl::InsertChain(const ChainImplPtr& chain) +ChainImplPtr EntityImpl::InsertChain(const ChainImplPtr& chain, bool deep) { ChainImplPtr dst_chain=this->InsertChain(chain->GetName()); dst_chain->Assign(*chain.get()); + if(deep) + { + ResidueImplList::iterator it=chain->GetResidueList().begin(), + it_end=chain->GetResidueList().end(); + for(;it!=it_end;++it){ + ResidueImplPtr res=*it; + dst_chain->AppendResidue(res, true); + } + } return dst_chain; } @@ -139,20 +147,7 @@ void EntityImpl::ReplicateHierarchy(EntityImplPtr dest) 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()); - for (ResidueImplList::iterator j=src_chain->GetResidueList().begin(), - e2=src_chain->GetResidueList().end(); j!=e2; ++j) { - ResidueImplPtr src_res=*j; - ResidueImplPtr dst_res=dst_chain->AppendResidue(src_res); - for (AtomImplList::iterator k=src_res->GetAtomList().begin(), - e3=src_res->GetAtomList().end(); k!=e3; ++k) { - AtomImplPtr src_atom=*k; - AtomImplPtr dst_atom=dst_res->InsertAtom(src_atom); - dst_atom->SetIndex(src_atom->GetIndex()); - } - } + dest->InsertChain(src_chain,true); } } @@ -244,21 +239,6 @@ int EntityImpl::GetChainCount() const return static_cast<int>(chain_list_.size()); } -const geom::Mat4& EntityImpl::GetTransfMatrix() const -{ - return transformation_matrix_; -} - -const geom::Mat4& EntityImpl::GetInvTransfMatrix() const -{ - return inverse_transformation_matrix_; -} - -bool EntityImpl::IsTransfIdentity() const -{ - return identity_transf_; -} - EntityImpl::~EntityImpl() { // notify all observers of pending destruct @@ -322,23 +302,18 @@ Real EntityImpl::GetMass() const { AtomImplPtr EntityImpl::CreateAtom(const ResidueImplPtr& rp, const String& name, - const geom::Vec3& pos, + const geom::Vec3& pos2, const String& ele) { #if MAKE_SHARED_AVAILABLE AtomImplPtr ap=boost::make_shared<AtomImpl>(shared_from_this(), rp, name, - pos, ele,next_index_++); + pos2, ele,next_index_++); #else - AtomImplPtr ap(new AtomImpl(shared_from_this(), rp, name, pos, ele, next_index_++)); + AtomImplPtr ap(new AtomImpl(shared_from_this(), rp, name, pos2, ele, next_index_++)); #endif - if (!identity_transf_) { - geom::Vec3 transformed_pos = geom::Vec3(transformation_matrix_*geom::Vec4(pos)); - ap->TransformedPos()=transformed_pos; - atom_organizer_.Add(ap,transformed_pos); - } else { - ap->TransformedPos()=pos; - atom_organizer_.Add(ap,pos); - } + geom::Vec3 pos = has_transform_ ? transform_.Apply(pos2) : pos2; + ap->TransformedPos()=pos; + atom_organizer_.Add(ap,pos); atom_map_.insert(AtomImplMap::value_type(ap.get(),ap)); return ap; } @@ -760,21 +735,25 @@ void EntityImpl::Apply(EntityVisitor& v) v.OnExit(); } -void EntityImpl::ApplyTransform(const geom::Mat4 transfmat) +void EntityImpl::ApplyTransform(const geom::Transform& tf) { - geom::Mat4 updated_transformation_matrix=transfmat*transformation_matrix_; - this->SetTransform(updated_transformation_matrix); + SetTransform(transform_.Apply(tf)); } -void EntityImpl::SetTransform(const geom::Mat4 transfmat) +void EntityImpl::SetTransform(const geom::Transform& tf) { - transformation_matrix_=transfmat; - inverse_transformation_matrix_=Invert(transformation_matrix_); - identity_transf_ = (transformation_matrix_==geom::Mat4()); + transform_=tf; + has_transform_=true; this->UpdateTransformedPos(); this->MarkOrganizerDirty(); } +void EntityImpl::ClearTransform() +{ + has_transform_=false; + SetTransform(geom::Transform()); +} + void EntityImpl::AttachObserver(const EntityObserverPtr& o) { observer_map_.insert(EntityObserverMap::value_type(o.get(),o)); @@ -798,7 +777,8 @@ void EntityImpl::Swap(EntityImpl& impl) 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_); + std::swap(transform_,impl.transform_); + std::swap(has_transform_,impl.has_transform_); atom_organizer_.Swap(impl.atom_organizer_); fragment_list_.swap(impl.fragment_list_); observer_map_.swap(impl.observer_map_); @@ -1194,7 +1174,10 @@ void EntityImpl::RenameChain(ChainImplPtr chain, const String& new_name) void EntityImpl::UpdateTransformedPos(){ for(AtomImplMap::iterator it = atom_map_.begin();it!=atom_map_.end();++it) { - it->second->TransformedPos()=geom::Vec3(transformation_matrix_*geom::Vec4(it->second->OriginalPos())); + it->second->TransformedPos()=has_transform_ ? transform_.Apply(it->second->OriginalPos()) : it->second->OriginalPos(); + } + for(ChainImplList::iterator cit=chain_list_.begin();cit!=chain_list_.end();++cit) { + (*cit)->UpdateTransformedPos(); } } diff --git a/modules/mol/base/src/impl/entity_impl.hh b/modules/mol/base/src/impl/entity_impl.hh index ccbf85b449cdf035493096c73157a485dc9baea8..c95bef408db5c911b40b71b6ae460baa5890b827 100644 --- a/modules/mol/base/src/impl/entity_impl.hh +++ b/modules/mol/base/src/impl/entity_impl.hh @@ -109,7 +109,9 @@ public: /// \brief insert a new chain based on parameters of the given chain /// /// The chain will have no residues and atoms - ChainImplPtr InsertChain(const ChainImplPtr& chain); + // force deep to be set explicitely, because it is better than implicit + // (and since we are on the impl level interface consistency isn't that critical) + ChainImplPtr InsertChain(const ChainImplPtr& chain, bool deep); ConnectorImplP Connect(const AtomImplPtr& first, const AtomImplPtr& second, Real len, Real theta, Real phi, unsigned char bond_order); @@ -143,9 +145,12 @@ public: void UpdateFromXCS(); void Apply(EntityVisitor& v); - void ApplyTransform(const geom::Mat4 transfmat); + void ApplyTransform(const geom::Transform& t); - void SetTransform(const geom::Mat4 transfmat); + void SetTransform(const geom::Transform& t); + const geom::Transform& GetTransform() const {return transform_;} + bool HasTransform() const {return has_transform_;} + void ClearTransform(); void AttachObserver(const EntityObserverPtr& o); void DetachObserver(const EntityObserverPtr& o); @@ -198,14 +203,6 @@ public: //! Get number of chains int GetChainCount() const; - //! Get transformation matrix - const geom::Mat4& GetTransfMatrix() const; - - //! Get inverse transformation matrix - const geom::Mat4& GetInvTransfMatrix() const; - - bool IsTransfIdentity() const; - const ChainImplList& GetChainList() const { return chain_list_; } ChainImplList& GetChainList() { return chain_list_; } @@ -266,10 +263,8 @@ private: ConnectorImplMap connector_map_; TorsionImplMap torsion_map_; - geom::Mat4 transformation_matrix_; - geom::Mat4 inverse_transformation_matrix_; - bool identity_transf_; - + geom::Transform transform_; + bool has_transform_; SpatialAtomOrganizer atom_organizer_; FragmentImplList fragment_list_; diff --git a/modules/mol/base/src/impl/residue_impl.cc b/modules/mol/base/src/impl/residue_impl.cc index 1e0fa1d461662e1895f6d8dd5bbeb7d8a58479f6..29fee9883e5a8381eac4c12d3d75a194f007de44 100644 --- a/modules/mol/base/src/impl/residue_impl.cc +++ b/modules/mol/base/src/impl/residue_impl.cc @@ -69,7 +69,8 @@ AtomImplPtr ResidueImpl::InsertAtom(const AtomImplPtr& atom) dst_atom->SetState(atom->GetState()); dst_atom->SetBFactor(atom->GetBFactor()); dst_atom->SetOccupancy(atom->GetOccupancy()); - dst_atom->SetHetAtom(atom->IsHetAtom()); + dst_atom->SetHetAtom(atom->IsHetAtom()); + dst_atom->SetIndex(atom->GetIndex()); if (!atom->HasDefaultProps()) { dst_atom->SetRadius(atom->GetRadius()); @@ -118,9 +119,16 @@ geom::Vec3 ResidueImpl::GetAltAtomPos(const AtomImplPtr& atom, throw Error("No alt atom group '"+group+"'"); } const AtomGroup& g=i->second; + EntityImplPtr eip=GetEntity(); for (AtomGroupEntryList::const_iterator j=g.atoms.begin(), e=g.atoms.end(); j!=e; ++j) { if (atom==j->atom.lock()) { + // the alternate entry positions are stored as original, and + // are returned as original as well ?! at least that is what + // the unit test seems to require + // also, the PDB writer currently expects this behavior, so + // if it is changed here, it must be changed there as well + //return eip->HasTransform() ? eip->GetTransform().Apply(j->pos) : j->pos; return j->pos; } } @@ -626,14 +634,11 @@ bool ResidueImpl::SwitchAtomPos(const String& group) { AtomGroup& agr=i->second; AtomGroupEntryList::iterator j=agr.atoms.begin(); for (; j!=agr.atoms.end(); ++j) { - AtomGroupEntry& entry=*j; assert(!entry.atom.expired()); entry.atom.lock()->OriginalPos()=entry.pos; - EntityHandle ent = entry.atom.lock()->GetEntity(); - geom::Mat4 transf_matrix = ent.GetTransformationMatrix(); - geom::Vec3 transf_pos = geom::Vec3(transf_matrix*geom::Vec4(entry.pos)); - entry.atom.lock()->TransformedPos()=transf_pos; + EntityImplPtr eip = entry.atom.lock()->GetEntity(); + entry.atom.lock()->TransformedPos() = eip->GetTransform().Apply(entry.pos); entry.atom.lock()->SetBFactor(j->b_factor); entry.atom.lock()->SetOccupancy(j->occ); } @@ -671,4 +676,25 @@ String ResidueImpl::GetStringProperty(Prop::ID prop_id) const } } +void ResidueImpl::UpdateTransformedPos() +{ + /* + the alt atom positions always store the original pos; hence the below code + is not necessary; however, it isn't clear (at least to me (AP)) if the + AtomImplPtr in the alt group is supposed to be modified here, or if this is + already taken care of in EntityImpl::UpdateTransformedPos() + */ +#if 0 + geom::Transform tf = GetEntity()->GetTransform(); + for(AtomEntryGroups::iterator git=alt_groups_.begin(); git!=alt_groups_.end();++git) { + for(AtomGroupEntryList::iterator lit=git->second.atoms.begin(); lit!=git->second.atoms.end();++lit) { + AtomImplPtr atom=lit->atom.lock().get(); + geom::Vec3 tpos=tf.Apply(atom->OriginalPos()); + atom->TransformedPos()=tpos; + lit->pos=atom->tpos; + } + } +#endif +} + }}} // ns diff --git a/modules/mol/base/src/impl/residue_impl.hh b/modules/mol/base/src/impl/residue_impl.hh index 24f829c6922bdbfdcc0ee8645cbec80e4ff49f88..91b6843e78ab8de6ab7034302aea3708595487a0 100644 --- a/modules/mol/base/src/impl/residue_impl.hh +++ b/modules/mol/base/src/impl/residue_impl.hh @@ -223,6 +223,9 @@ public: bool IsLigand() const { return ligand_; } void SetIsLigand(bool flag) { ligand_=flag; } + + void UpdateTransformedPos(); + private: void AddAltAtom(const String& group, const AtomImplPtr& atom, const geom::Vec3& position, Real occ, Real b_factor); diff --git a/modules/mol/base/src/view_op.cc b/modules/mol/base/src/view_op.cc index 6e4227e741d0faa02d5b1a902b1d63be0050aee2..6b8aebad85b78a9600e354b774cd512e990ccf54 100644 --- a/modules/mol/base/src/view_op.cc +++ b/modules/mol/base/src/view_op.cc @@ -296,7 +296,7 @@ public: virtual bool VisitResidue(const ResidueHandle& res) { - res_=chain_->AppendResidue(res.Impl()); + res_=chain_->AppendResidue(res.Impl(),false); return true; } diff --git a/modules/mol/base/src/xcs_editor.cc b/modules/mol/base/src/xcs_editor.cc index 0c2454b187c8d29902b8380e4caf3b7969db3fe5..5596e3962d1479921f2c5b8ae5108d0c92ee9b38 100644 --- a/modules/mol/base/src/xcs_editor.cc +++ b/modules/mol/base/src/xcs_editor.cc @@ -74,14 +74,11 @@ void XCSEditor::SetAtomTransformedPos(const AtomHandle& atom, const geom::Vec3& position) { CheckHandleValidity(atom); + impl::EntityImplPtr eip=ent_.Impl(); atom.Impl()->TransformedPos()=position; - if(ent_.Impl()->IsTransfIdentity()) { - atom.Impl()->OriginalPos()=position; - } else { - atom.Impl()->OriginalPos() = geom::Vec3(ent_.Impl()->GetInvTransfMatrix()*geom::Vec4(position)); - } - ent_.Impl()->MarkICSDirty(); - ent_.Impl()->MarkOrganizerDirty(); + atom.Impl()->OriginalPos() = eip->HasTransform() ? eip->GetTransform().ApplyInverse(position) : position; + eip->MarkICSDirty(); + eip->MarkOrganizerDirty(); this->Update(); } @@ -89,17 +86,14 @@ namespace { template<typename T> void set_transformed_pos(impl::EntityImpl* ent, const AtomHandleList& alist, T *positions) { - bool has_tf=ent->IsTransfIdentity(); + bool has_tf=ent->HasTransform(); for(AtomHandleList::const_iterator ait=alist.begin();ait!=alist.end();++ait) { if(ait->IsValid()) { - ait->Impl()->TransformedPos()[0]=static_cast<Real>(positions[0]); - ait->Impl()->TransformedPos()[1]=static_cast<Real>(positions[1]); - ait->Impl()->TransformedPos()[2]=static_cast<Real>(positions[2]); - if(has_tf) { - ait->Impl()->OriginalPos()=ait->Impl()->TransformedPos(); - } else { - ait->Impl()->OriginalPos() = geom::Vec3(ent->GetInvTransfMatrix()*geom::Vec4(ait->Impl()->TransformedPos())); - } + geom::Vec3& tpos=ait->Impl()->TransformedPos(); + tpos[0]=static_cast<Real>(positions[0]); + tpos[1]=static_cast<Real>(positions[1]); + tpos[2]=static_cast<Real>(positions[2]); + ait->Impl()->OriginalPos()=has_tf ? ent->GetTransform().ApplyInverse(tpos) : tpos; } positions+=3; } @@ -124,14 +118,11 @@ void XCSEditor::SetAtomOriginalPos(const AtomHandle& atom, const geom::Vec3& position) { CheckHandleValidity(atom); + impl::EntityImplPtr eip=ent_.Impl(); atom.Impl()->OriginalPos()=position; - if(ent_.Impl()->IsTransfIdentity()) { - atom.Impl()->TransformedPos()=position; - } else { - atom.Impl()->TransformedPos() = geom::Vec3(ent_.Impl()->GetTransfMatrix()*geom::Vec4(position)); - } - ent_.Impl()->MarkICSDirty(); - ent_.Impl()->MarkOrganizerDirty(); + atom.Impl()->TransformedPos() = eip->HasTransform() ? eip->GetTransform().Apply(position) : position; + eip->MarkICSDirty(); + eip->MarkOrganizerDirty(); this->Update(); } @@ -139,17 +130,14 @@ namespace { template<typename T> void set_original_pos(impl::EntityImpl* ent, const AtomHandleList& alist, T *positions) { - bool has_tf=ent->IsTransfIdentity(); + bool has_tf=ent->HasTransform(); for(AtomHandleList::const_iterator ait=alist.begin();ait!=alist.end();++ait) { if(ait->IsValid()) { - ait->Impl()->OriginalPos()[0]=static_cast<Real>(positions[0]); - ait->Impl()->OriginalPos()[1]=static_cast<Real>(positions[1]); - ait->Impl()->OriginalPos()[2]=static_cast<Real>(positions[2]); - if(has_tf) { - ait->Impl()->TransformedPos()=ait->Impl()->OriginalPos(); - } else { - ait->Impl()->TransformedPos() = geom::Vec3(ent->GetTransfMatrix()*geom::Vec4(ait->Impl()->OriginalPos())); - } + geom::Vec3& opos=ait->Impl()->OriginalPos(); + opos[0]=static_cast<Real>(positions[0]); + opos[1]=static_cast<Real>(positions[1]); + opos[2]=static_cast<Real>(positions[2]); + ait->Impl()->TransformedPos()= has_tf ? ent->GetTransform().Apply(opos) : opos; } positions+=3; } @@ -186,6 +174,13 @@ void XCSEditor::SetAtomPos(const AtomHandleList& alist, double *positions) } void XCSEditor::ApplyTransform(const geom::Mat4& transform) +{ + geom::Transform tf; + tf.SetMatrix(transform); + this->ApplyTransform(tf); +} + +void XCSEditor::ApplyTransform(const geom::Transform& transform) { ent_.Impl()->ApplyTransform(transform); ent_.Impl()->UpdateTransformedPos(); @@ -194,8 +189,14 @@ void XCSEditor::ApplyTransform(const geom::Mat4& transform) this->Update(); } - void XCSEditor::SetTransform(const geom::Mat4& transform) +{ + geom::Transform tf; + tf.SetMatrix(transform); + this->SetTransform(tf); +} + +void XCSEditor::SetTransform(const geom::Transform& transform) { ent_.Impl()->SetTransform(transform); ent_.Impl()->UpdateTransformedPos(); @@ -204,7 +205,6 @@ void XCSEditor::SetTransform(const geom::Mat4& transform) this->Update(); } - void XCSEditor::Update() { if (GetMode()==UNBUFFERED_EDIT) { diff --git a/modules/mol/base/src/xcs_editor.hh b/modules/mol/base/src/xcs_editor.hh index 73d96a652829932c469a6a0382093de7fd53b5f4..a7cc317b2e5273b62211b03a8d04559de97f0fff 100644 --- a/modules/mol/base/src/xcs_editor.hh +++ b/modules/mol/base/src/xcs_editor.hh @@ -98,10 +98,11 @@ public: /// This transformation is applied \em after the transformation /// already stored in the entity void ApplyTransform(const geom::Mat4& transform); + void ApplyTransform(const geom::Transform& transform); /// \brief apply a new transformation to all atoms - void SetTransform(const geom::Mat4& transform); + void SetTransform(const geom::Transform& transform); /// \brief immediately update internal coordinate system void UpdateICS(); diff --git a/modules/mol/base/tests/test_chain.cc b/modules/mol/base/tests/test_chain.cc index ee4d933d0c095766079bb4278774d41d97a74ae3..39ffd35e205cd320cc926af7e4a440f838109b2c 100644 --- a/modules/mol/base/tests/test_chain.cc +++ b/modules/mol/base/tests/test_chain.cc @@ -87,16 +87,38 @@ BOOST_AUTO_TEST_CASE(test_comparison) BOOST_CHECK(cc==ch1); } - BOOST_AUTO_TEST_CASE(throw_invalid_chain_handle) { EntityHandle ent=CreateEntity(); - ChainHandle chain=ent.FindChain("A"); - BOOST_CHECK_THROW(CheckHandleValidity(chain), InvalidHandle); + ChainHandle ch=ent.FindChain("A"); + BOOST_CHECK_THROW(CheckHandleValidity(ch), InvalidHandle); XCSEditor edi=ent.EditXCS(); edi.InsertChain("A"); - chain=ent.FindChain("A"); - BOOST_CHECK_NO_THROW(CheckHandleValidity(chain)); + ch=ent.FindChain("A"); + BOOST_CHECK_NO_THROW(CheckHandleValidity(ch)); + + + EntityHandle eh1 = CreateEntity(); + XCSEditor e1=eh1.EditXCS(); + ChainHandle chain = e1.InsertChain("C"); + ResidueHandle res1 = e1.AppendResidue(chain, "FOO", ResNum(13)); + AtomHandle atom1 = e1.InsertAtom(res1, "X1",geom::Vec3()); + AtomHandle atom2 = e1.InsertAtom(res1, "X2",geom::Vec3()); + ResidueHandle res2 = e1.AppendResidue(chain, "FOO", ResNum(42)); + e1.InsertAtom(res2, "X1",geom::Vec3()); + e1.InsertAtom(res2, "X2",geom::Vec3()); + + EntityHandle eh2=CreateEntity(); + XCSEditor e2=eh2.EditXCS(); + ChainHandle inserted_chain1 = e2.InsertChain("Q",chain); + res1.SetIntProp("amazing",42); + ResidueHandle inserted_residue1 = e2.AppendResidue(inserted_chain1,res1); + BOOST_CHECK(inserted_residue1!=res1); + BOOST_CHECK(eh2.GetResidueCount()==1); + BOOST_CHECK(eh2.GetAtomCount()==0); + BOOST_CHECK(inserted_residue1.HasProp("amazing")); + ResidueHandle inserted_residue2 = e2.AppendResidue(inserted_chain1,res2,true); + BOOST_CHECK(eh2.GetAtomCount()==2); } BOOST_AUTO_TEST_CASE(throw_invalid_chain_view) diff --git a/modules/mol/base/tests/test_entity.cc b/modules/mol/base/tests/test_entity.cc index d8ecd8f3b9a9007e84549d6b4a20e302a1a5fe67..767b68bb3ba14f55eca9afde0a3158c5fcab06eb 100644 --- a/modules/mol/base/tests/test_entity.cc +++ b/modules/mol/base/tests/test_entity.cc @@ -136,8 +136,24 @@ BOOST_AUTO_TEST_CASE(entity_creator) BOOST_CHECK(eh.GetAtomCount()==2); BOOST_CHECK(eh.GetAtomCount()==chain.GetAtomCount()); - BOOST_CHECK(eh.GetResidueCount()==chain.GetResidueCount()); - + BOOST_CHECK(eh.GetResidueCount()==chain.GetResidueCount()); + + chain.SetIntProp("amazing",42); + EntityHandle eh2 = CreateEntity(); + XCSEditor e2 = eh2.EditXCS(); + ChainHandle inserted_chain=e2.InsertChain("Q",chain); + BOOST_CHECK(eh2.GetChainCount()==1); + BOOST_CHECK(eh2.GetResidueCount()==0); + BOOST_CHECK(eh2.GetAtomCount()==0); + BOOST_CHECK(inserted_chain.HasProp("amazing")); + BOOST_CHECK(eh2.FindChain("Q").IsValid()); + + EntityHandle eh3 = CreateEntity(); + XCSEditor e3 = eh3.EditXCS(); + e3.InsertChain("Q",chain,true); + BOOST_CHECK(eh3.GetResidueCount()==1); + BOOST_CHECK(eh3.GetAtomCount()==2); + EntityVisitor v; eh.Apply(v); } @@ -179,14 +195,12 @@ BOOST_AUTO_TEST_CASE(transformation) BOOST_CHECK(within_list1[0]==atom1); BOOST_CHECK(within_list1[1]==atom2); - BOOST_CHECK(eh.IsTransformationIdentity()==true); + BOOST_CHECK(eh.HasTransform()==false); geom::Transform trans; trans.ApplyZAxisRotation(90.0); - geom::Mat4 mat = trans.GetMatrix(); - - e.ApplyTransform(mat); - BOOST_CHECK(eh.IsTransformationIdentity()==false); + e.ApplyTransform(trans); + BOOST_CHECK(eh.HasTransform()==true); geom::Vec3 orig_atom1=geom::Vec3(1.0,0.0,0.0); geom::Vec3 orig_atom2=geom::Vec3(0.0,2.0,0.0); @@ -205,11 +219,9 @@ BOOST_AUTO_TEST_CASE(transformation) geom::Transform trans2; trans2.ApplyXAxisTranslation(3.5); - geom::Mat4 mat2 = trans2.GetMatrix(); + e.ApplyTransform(trans2); - e.ApplyTransform(mat2); - - BOOST_CHECK(eh.IsTransformationIdentity()==false); + BOOST_CHECK(eh.HasTransform()==true); tr_atom1=geom::Vec3(3.5,-1.0,0.0); tr_atom2=geom::Vec3(5.5,0.0,0.0); @@ -253,7 +265,7 @@ BOOST_AUTO_TEST_CASE(transformation) geom::Mat4 identity; e.SetTransform(identity); - BOOST_CHECK(eh.IsTransformationIdentity()==true); + //BOOST_CHECK(eh.HasTransform()==false); BondHandle bond1 = e.Connect(atom1,atom2); BondHandle bond2 = e.Connect(atom1,atom3); @@ -261,9 +273,9 @@ BOOST_AUTO_TEST_CASE(transformation) BOOST_CHECK(bond1.GetLength()==1.5); BOOST_CHECK(bond2.GetLength()==2.0); - e.SetTransform(mat); - - BOOST_CHECK(eh.IsTransformationIdentity()==false); + e.SetTransform(trans); + + //BOOST_CHECK(eh.HasTransform()==true); BOOST_CHECK(bond1.GetLength()==1.5); BOOST_CHECK(bond2.GetLength()==2.0); diff --git a/scripts/ost_config.in b/scripts/ost_config.in index 5894bdb12c62241d556e04fb909eb9f83a17c5ef..f756d7cd30c29db720aeba659643c18bb872e4c9 100644 --- a/scripts/ost_config.in +++ b/scripts/ost_config.in @@ -30,9 +30,8 @@ export PATH="$DNG_BINDIR:${PATH}" export DYLD_FRAMEWORK_PATH="$DNG_LIBDIR:${DYLD_FRAMEWORK_PATH}" export DYLD_LIBRARY_PATH="$DNG_LIBDIR:${DYLD_LIBRARY_PATH}" export LD_LIBRARY_PATH="$DNG_LIBDIR:${LD_LIBRARY_PATH}" -# set QT_PLUGIN_PATH and PYTHONPATH for bundle (commented except in linux bundles) +# set QT_PLUGIN_PATH for bundle (commented except in linux bundles) #export QT_PLUGIN_PATH="$BIN_DIR/plugins" -#export PYTHONPATH="$DNG_ROOT/@LIBDIR@/python@PYTHON_VERSION@:$OST_ADDITIONAL_PYTHONPATH" # retrieve absolute path to python executable pyexec="@PYTHON_BINARY@" diff --git a/tools/molck/main.cc b/tools/molck/main.cc index 9dd212a51c9dd2bc616f5f9e24a88c4015ff2533..2a5e8e7eac780c856d3345464c93339f28a0c2df 100644 --- a/tools/molck/main.cc +++ b/tools/molck/main.cc @@ -2,6 +2,8 @@ #include <boost/program_options.hpp> #include <boost/filesystem/path.hpp> #include <boost/filesystem/convenience.hpp> +#include <ost/base.hh> +#include <ost/boost_filesystem_helper.hh> #include <ost/platform.hh> #include <ost/conop/model_check.hh> #include <ost/conop/conop.hh> @@ -73,11 +75,7 @@ CompoundLibPtr load_compound_lib(const String& custom_path) fs::path share_path = path_only.branch_path(); share_path = share_path / "share" / "openstructure" / "compounds.chemlib"; - #if BOOST_FILESYSTEM_VERSION==3 || BOOST_VERSION<103400 - String share_path_string=share_path.string(); - #else - String share_path_string=share_path.file_string(); - #endif + String share_path_string=BFPathToString(share_path); if (fs::exists(share_path_string)) { return CompoundLib::Load(share_path_string); @@ -369,11 +367,7 @@ int main(int argc, char *argv[]) if (write_to_file) { fs::path input_file_path(files[i]); fs::path input_filename = input_file_path.stem(); - #if BOOST_FILESYSTEM_VERSION==3 || BOOST_VERSION<103400 - String input_filename_string=input_filename.string(); - #else - String input_filename_string=input_filename.file_string(); - #endif + String input_filename_string=BFPathToString(input_filename); size_t replstart =output_blueprint_string.find('%'); String output_blueprint_string_copy = output_blueprint_string; if (replstart != String::npos) {