├── .gitattributes ├── .gitignore ├── CMakeLists.txt ├── README.md ├── cmake ├── CXXFeatures.cmake ├── DownloadProject.CMakeLists.cmake.in ├── DownloadProject.cmake ├── FindMPIR.cmake ├── TMeshKernelDependencies.cmake ├── TMeshKernelDownloadExternal.cmake ├── UseColors.cmake ├── Warnings.cmake └── mpir.cmake ├── include ├── basics.h ├── coordinates.h ├── expansion.h ├── mixedPredicates.h ├── point.h ├── tmesh_kernel.h └── unprecise_numbers.h ├── lgpl.txt ├── mpir ├── README.txt └── vs2013 │ ├── mpir.h │ ├── mpir32.lib │ └── mpir64.lib ├── src ├── coordinates.cpp ├── expansion.cpp ├── mixedPredicates.cpp ├── orientation.cpp ├── point.cpp └── tmesh.cpp └── tests ├── CMakeLists.txt ├── main.cpp └── test_kernel.cpp /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.obj 2 | 3 | *.o 4 | 5 | *.ilk 6 | 7 | *.exe 8 | 9 | *.sdf 10 | 11 | *.suo 12 | 13 | build 14 | 15 | lib64 16 | 17 | lib 18 | 19 | bin64 20 | 21 | bin 22 | 23 | src/test_kernel.cpp 24 | 25 | mpir/mpir32.lib 26 | 27 | mpir/mpir64.lib 28 | 29 | mpir/mpir.h 30 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | cmake_minimum_required(VERSION 3.1) 3 | project(TMesh_Kernel) 4 | ################################################################################ 5 | 6 | # Uncomment and adapt the following definition after having downloaded 7 | # mpir and compiled it for 64bit. 8 | #set(MPIR_LOCATION "D:/SOFTWARE/mpir-master/msvc/vs19/lib_mpir_gc/x64/Release") 9 | 10 | 11 | ################################################################################ 12 | 13 | 14 | # Options for enabling/disabling optional libraries 15 | option(USE_LAZY_KERNEL "Use lazy kernel" ON) 16 | 17 | ################################################################################ 18 | # library 19 | ################################################################################ 20 | 21 | if(${USE_LAZY_KERNEL}) 22 | if(NOT DEFINED MPIR_LOCATION) 23 | message(FATAL_ERROR "MPIR_LOCATION is undefined. Please set it on line 8 in CMakeLists.txt") 24 | endif(NOT DEFINED MPIR_LOCATION) 25 | set(TMESH_LIB_PATH "kernel_Lazy64") 26 | else() 27 | set(TMESH_LIB_PATH "kernel_Fast64") 28 | endif() 29 | 30 | add_library(${TMESH_LIB_PATH} STATIC 31 | src/coordinates.cpp 32 | src/expansion.cpp 33 | src/mixedPredicates.cpp 34 | src/orientation.cpp 35 | src/point.cpp 36 | src/tmesh.cpp 37 | ) 38 | 39 | if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") 40 | target_compile_options(${TMESH_LIB_PATH} PUBLIC -frounding-math) 41 | set(MPIR_LIB ${MPIR_LOCATION}/mpir.a) 42 | elseif(${CMAKE_SYSTEM_NAME} MATCHES "Windows") 43 | target_compile_options(${TMESH_LIB_PATH} PUBLIC "/fp:strict") 44 | target_compile_definitions(${TMESH_LIB_PATH} PUBLIC -D_CRT_SECURE_NO_WARNINGS) 45 | set(MPIR_LIB ${MPIR_LOCATION}/mpir.lib) 46 | endif() 47 | 48 | if(${USE_LAZY_KERNEL}) 49 | target_compile_definitions(${TMESH_LIB_PATH} PUBLIC -DUSE_LAZY_KERNEL) 50 | target_compile_definitions(${TMESH_LIB_PATH} PUBLIC -DUSE_HYBRID_KERNEL) 51 | endif() 52 | 53 | if(CMAKE_SIZEOF_VOID_P EQUAL 8) 54 | target_compile_definitions(${TMESH_LIB_PATH} PUBLIC -DIS64BITPLATFORM) 55 | endif() 56 | 57 | # Public include directory 58 | target_include_directories(${TMESH_LIB_PATH} PUBLIC include) 59 | 60 | # Use C++14 61 | target_compile_features(${TMESH_LIB_PATH} PUBLIC ${CXX14_FEATURES}) 62 | 63 | 64 | ################################################################################ 65 | # Required libraries 66 | ################################################################################ 67 | 68 | if(${USE_LAZY_KERNEL}) 69 | target_include_directories(${TMESH_LIB_PATH} PUBLIC ${MPIR_LOCATION}/) 70 | target_link_libraries(${TMESH_LIB_PATH} PUBLIC ${MPIR_LIB}) 71 | endif() 72 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ---------------------------- 2 | TMesh_Kernel 3 | ---------------------------- 4 | 5 | by Marco Attene 6 | 7 | Consiglio Nazionale delle Ricerche 8 | Istituto di Matematica Applicata e Tecnologie Informatiche 9 | Sezione di Genova 10 | IMATI-GE / CNR 11 | 12 | TMesh_Kernel is a C++ library providing a hybrid arithmetic kernel for geometric computation in 3D. 13 | It includes hybrid numbers, 3D vectors and points along with standard operations, geometric predicates, geometric constructors, and intersections. 14 | The hybrid kernel combines the efficiency of standard floating point computation with the robustness of rational arithmetic. 15 | In TMesh_Kernel, geometric predicates are always exact, whereas geometric constructions can be either approximate or exact, depending on the programmer's choice. Programs based on TMesh_Kernel can dynamically switch between rational and floating point arithmetic. 16 | TMesh_Kernel is at the base of a larger project called ImatiSTL. 17 | 18 | ------------------- 19 | Citation policy 20 | -------------------- 21 | You are free to use TMesh_Kernel according to the licensing terms specified at the end of this document. 22 | If you use TMesh_Kernel for research purposes and produce publications, please cite the following paper 23 | that describes the underlying hybrid paradigm: 24 | 25 | > Marco Attene. ImatiSTL - Fast and Reliable Mesh Processing with a Hybrid Kernel. 26 | Springer LNCS Transactions on Computational Science, Vol. XXIX, pp. 86-96, 2017. 27 | 28 | Note that the distinction between 'approximated' and 'filtered' described in the paper has been deprecated 29 | in the code, where the only two possibilities are 'filtered' and 'precise'. This simplification is because 30 | the performance loss of a filtered kernel wrt an approximated kernel is mostly negligible. 31 | 32 | 33 | ------------------- 34 | Documentation 35 | ------------------- 36 | 37 | The aforementioned paper is the best source of information to understand the hybrid arithmetic paradigm. 38 | However, the paper is not meant to be a comprehensive programmer's guide. 39 | The file tests/test_kernel.cpp is a good starting point to start playing with the library. 40 | It has been extensively commented to step-by-step explain how to use the main library features. 41 | Other than that, please look at the comments within the header files or use doxygen to 42 | produce documentation in a more readable format. 43 | 44 | 45 | ------------------- 46 | System Requirements 47 | -------------------- 48 | 49 | TMesh_Kernel has been tested on 64 bit PCs running: 50 | - Microsoft Windows OS with MSVC 51 | - Linux with standard gcc/g++ development environment 52 | - Mac OSX 53 | 54 | TMesh_Kernel exploits MPIR to deal with arbitrarily precise rational numbers. 55 | MPIR is an independent software licensed under the terms of GNU LGPL v3. 56 | Please look at mpir/README.txt for further information. 57 | 58 | ------------------------------------- 59 | Building the tree in LAZY-HYBRID mode 60 | ------------------------------------- 61 | 62 | Before building TMesh_Kernel, you must obtain and build MPIR. 63 | Please look at mpir/README.txt for instructions. 64 | 65 | Once done with MPIR, return to the directory containing this README file, 66 | edit CMakeLists.txt at line 8 to enter the path containing mpir.a (or mpir.lib on Windows). 67 | Then type: 68 | ``` 69 | mkdir build 70 | cd build 71 | cmake .. 72 | ``` 73 | 74 | This will produce an appropriate building configuration for your system. 75 | On Windows MSVC, this will produce a TMesh_Kernel.sln file. 76 | On Linux/OSx, this will produce a Makefile. 77 | Use it as usual to compile TMesh_Kernel. 78 | 79 | ------------------------------ 80 | Building the tree in FAST mode 81 | ------------------------------ 82 | 83 | In this mode, the hybrid kernel is disabled. 84 | MPIR is not needed to compile in this mode. 85 | Just run the following commands: 86 | ``` 87 | mkdir build 88 | cd build 89 | cmake -DUSE_LAZY_KERNEL=OFF .. 90 | ``` 91 | 92 | and proceed as for the LAZY-HYBRID mode. 93 | **Warning:** When compiled in FAST mode, rational numbers are not supported! 94 | If you need the hybrid arithmetic kernel, compile in LAZY-HYBRID mode. 95 | 96 | ------------------------------------- 97 | Using the library in LAZY-HYBRID mode 98 | ------------------------------------- 99 | 100 | C/C++ code using TMesh_Kernel must be compiled according to the following rules. 101 | 102 | **include path must include:** 103 | ``` 104 | $(TMESH_HOME)/include 105 | $(TMESH_HOME)/mpir 106 | ``` 107 | 108 | **preprocessor definitions** 109 | In all cases: `USE_HYBRID_KERNEL`, `USE_LAZY_KERNEL`, `IS64BITPLATFORM` 110 | 111 | **library path must include:** 112 | ``` 113 | $(TMESH_HOME)/lib64 114 | $(TMESH_HOME)/mpir 115 | ``` 116 | 117 | **static libraries to be linked** 118 | `kernel_Lazy64` 119 | `mpir` 120 | 121 | **other options to be set** 122 | Support for OpenMP might be active 123 | 124 | ------------------------------ 125 | Using the library in FAST mode 126 | ------------------------------ 127 | As above, but all the references to mpir are no longer necessary. 128 | Furthermore, the only preprocessor definition to be used is: 129 | `IS64BITPLATFORM` 130 | 131 | --------------------- 132 | Copyright and license 133 | --------------------- 134 | 135 | TMesh_Kernel 136 | Authors: Marco Attene 137 | 138 | Copyright(C) 2012: IMATI-GE / CNR 139 | 140 | IMATI-GE / CNR is Consiglio Nazionale delle Ricerche 141 | Istituto di Matematica Applicata e Tecnologie Informatiche 142 | Genova (Italy) 143 | 144 | TMesh_Kernel is free software; you can redistribute it and/or modify 145 | it under the terms of the GNU Lesser General Public License as published 146 | by the Free Software Foundation; either version 3 of the License, or (at 147 | your option) any later version. 148 | 149 | TMesh_Kernel is distributed in the hope that it will be useful, but 150 | WITHOUT ANY WARRANTY; without even the implied warranty of 151 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 152 | General Public License for more details. 153 | 154 | You should have received a copy of the GNU Lesser General Public License 155 | along with the TMesh_Kernel. If not, see http://www.gnu.org/licenses/. 156 | -------------------------------------------------------------------------------- /cmake/CXXFeatures.cmake: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | 3 | if(NOT (${CMAKE_VERSION} VERSION_LESS "3.8.0")) 4 | # For CMake 3.8 and above, we can use meta features directly provided by CMake itself 5 | set(CXX11_FEATURES cxx_std_11) 6 | set(CXX14_FEATURES cxx_std_14) 7 | set(CXX17_FEATURES cxx_std_17) 8 | return() 9 | endif() 10 | 11 | ################################################################################ 12 | 13 | set(CXX11_FEATURES 14 | cxx_auto_type 15 | cxx_constexpr 16 | ) 17 | 18 | set(CXX14_FEATURES 19 | cxx_generic_lambdas 20 | ) 21 | 22 | set(CXX17_FEATURES 23 | cxx_generic_lambdas 24 | ) 25 | 26 | ################################################################################ 27 | 28 | # https://cmake.org/cmake/help/v3.1/prop_gbl/CMAKE_CXX_KNOWN_FEATURES.html 29 | # cxx_aggregate_default_initializers Aggregate default initializers, as defined in N3605. 30 | # cxx_alias_templates Template aliases, as defined in N2258. 31 | # cxx_alignas Alignment control alignas, as defined in N2341. 32 | # cxx_alignof Alignment control alignof, as defined in N2341. 33 | # cxx_attributes Generic attributes, as defined in N2761. 34 | # cxx_attribute_deprecated deprecated]] attribute, as defined in N3760. 35 | # cxx_auto_type Automatic type deduction, as defined in N1984. 36 | # cxx_binary_literals Binary literals, as defined in N3472. 37 | # cxx_constexpr Constant expressions, as defined in N2235. 38 | # cxx_contextual_conversions Contextual conversions, as defined in N3323. 39 | # cxx_decltype_incomplete_return_types Decltype on incomplete return types, as defined in N3276. 40 | # cxx_decltype Decltype, as defined in N2343. 41 | # cxx_decltype_auto decltype(auto) semantics, as defined in N3638. 42 | # cxx_default_function_template_args Default template arguments for function templates, as defined in DR226 43 | # cxx_defaulted_functions Defaulted functions, as defined in N2346. 44 | # cxx_defaulted_move_initializers Defaulted move initializers, as defined in N3053. 45 | # cxx_delegating_constructors Delegating constructors, as defined in N1986. 46 | # cxx_deleted_functions Deleted functions, as defined in N2346. 47 | # cxx_digit_separators Digit separators, as defined in N3781. 48 | # cxx_enum_forward_declarations Enum forward declarations, as defined in N2764. 49 | # cxx_explicit_conversions Explicit conversion operators, as defined in N2437. 50 | # cxx_extended_friend_declarations Extended friend declarations, as defined in N1791. 51 | # cxx_extern_templates Extern templates, as defined in N1987. 52 | # cxx_final Override control final keyword, as defined in N2928, N3206 and N3272. 53 | # cxx_func_identifier Predefined __func__ identifier, as defined in N2340. 54 | # cxx_generalized_initializers Initializer lists, as defined in N2672. 55 | # cxx_generic_lambdas Generic lambdas, as defined in N3649. 56 | # cxx_inheriting_constructors Inheriting constructors, as defined in N2540. 57 | # cxx_inline_namespaces Inline namespaces, as defined in N2535. 58 | # cxx_lambdas Lambda functions, as defined in N2927. 59 | # cxx_lambda_init_captures Initialized lambda captures, as defined in N3648. 60 | # cxx_local_type_template_args Local and unnamed types as template arguments, as defined in N2657. 61 | # cxx_long_long_type long long type, as defined in N1811. 62 | # cxx_noexcept Exception specifications, as defined in N3050. 63 | # cxx_nonstatic_member_init Non-static data member initialization, as defined in N2756. 64 | # cxx_nullptr Null pointer, as defined in N2431. 65 | # cxx_override Override control override keyword, as defined in N2928, N3206 and N3272. 66 | # cxx_range_for Range-based for, as defined in N2930. 67 | # cxx_raw_string_literals Raw string literals, as defined in N2442. 68 | # cxx_reference_qualified_functions Reference qualified functions, as defined in N2439. 69 | # cxx_relaxed_constexpr Relaxed constexpr, as defined in N3652. 70 | # cxx_return_type_deduction Return type deduction on normal functions, as defined in N3386. 71 | # cxx_right_angle_brackets Right angle bracket parsing, as defined in N1757. 72 | # cxx_rvalue_references R-value references, as defined in N2118. 73 | # cxx_sizeof_member Size of non-static data members, as defined in N2253. 74 | # cxx_static_assert Static assert, as defined in N1720. 75 | # cxx_strong_enums Strongly typed enums, as defined in N2347. 76 | # cxx_thread_local Thread-local variables, as defined in N2659. 77 | # cxx_trailing_return_types Automatic function return type, as defined in N2541. 78 | # cxx_unicode_literals Unicode string literals, as defined in N2442. 79 | # cxx_uniform_initialization Uniform intialization, as defined in N2640. 80 | # cxx_unrestricted_unions Unrestricted unions, as defined in N2544. 81 | # cxx_user_literals User-defined literals, as defined in N2765. 82 | # cxx_variable_templates Variable templates, as defined in N3651. 83 | # cxx_variadic_macros Variadic macros, as defined in N1653. 84 | # cxx_variadic_templates Variadic templates, as defined in N2242. 85 | # cxx_template_template_parameters Template template parameters, as defined in ISO/IEC 14882:1998. 86 | -------------------------------------------------------------------------------- /cmake/DownloadProject.CMakeLists.cmake.in: -------------------------------------------------------------------------------- 1 | # Distributed under the OSI-approved MIT License. See accompanying 2 | # file LICENSE or https://github.com/Crascit/DownloadProject for details. 3 | 4 | cmake_minimum_required(VERSION 2.8.2) 5 | 6 | project(${DL_ARGS_PROJ}-download NONE) 7 | 8 | include(ExternalProject) 9 | ExternalProject_Add(${DL_ARGS_PROJ}-download 10 | ${DL_ARGS_UNPARSED_ARGUMENTS} 11 | SOURCE_DIR "${DL_ARGS_SOURCE_DIR}" 12 | BINARY_DIR "${DL_ARGS_BINARY_DIR}" 13 | CONFIGURE_COMMAND "" 14 | BUILD_COMMAND "" 15 | INSTALL_COMMAND "" 16 | TEST_COMMAND "" 17 | ) 18 | -------------------------------------------------------------------------------- /cmake/DownloadProject.cmake: -------------------------------------------------------------------------------- 1 | # Distributed under the OSI-approved MIT License. See accompanying 2 | # file LICENSE or https://github.com/Crascit/DownloadProject for details. 3 | # 4 | # MODULE: DownloadProject 5 | # 6 | # PROVIDES: 7 | # download_project( PROJ projectName 8 | # [PREFIX prefixDir] 9 | # [DOWNLOAD_DIR downloadDir] 10 | # [SOURCE_DIR srcDir] 11 | # [BINARY_DIR binDir] 12 | # [QUIET] 13 | # ... 14 | # ) 15 | # 16 | # Provides the ability to download and unpack a tarball, zip file, git repository, 17 | # etc. at configure time (i.e. when the cmake command is run). How the downloaded 18 | # and unpacked contents are used is up to the caller, but the motivating case is 19 | # to download source code which can then be included directly in the build with 20 | # add_subdirectory() after the call to download_project(). Source and build 21 | # directories are set up with this in mind. 22 | # 23 | # The PROJ argument is required. The projectName value will be used to construct 24 | # the following variables upon exit (obviously replace projectName with its actual 25 | # value): 26 | # 27 | # projectName_SOURCE_DIR 28 | # projectName_BINARY_DIR 29 | # 30 | # The SOURCE_DIR and BINARY_DIR arguments are optional and would not typically 31 | # need to be provided. They can be specified if you want the downloaded source 32 | # and build directories to be located in a specific place. The contents of 33 | # projectName_SOURCE_DIR and projectName_BINARY_DIR will be populated with the 34 | # locations used whether you provide SOURCE_DIR/BINARY_DIR or not. 35 | # 36 | # The DOWNLOAD_DIR argument does not normally need to be set. It controls the 37 | # location of the temporary CMake build used to perform the download. 38 | # 39 | # The PREFIX argument can be provided to change the base location of the default 40 | # values of DOWNLOAD_DIR, SOURCE_DIR and BINARY_DIR. If all of those three arguments 41 | # are provided, then PREFIX will have no effect. The default value for PREFIX is 42 | # CMAKE_BINARY_DIR. 43 | # 44 | # The QUIET option can be given if you do not want to show the output associated 45 | # with downloading the specified project. 46 | # 47 | # In addition to the above, any other options are passed through unmodified to 48 | # ExternalProject_Add() to perform the actual download, patch and update steps. 49 | # The following ExternalProject_Add() options are explicitly prohibited (they 50 | # are reserved for use by the download_project() command): 51 | # 52 | # CONFIGURE_COMMAND 53 | # BUILD_COMMAND 54 | # INSTALL_COMMAND 55 | # TEST_COMMAND 56 | # 57 | # Only those ExternalProject_Add() arguments which relate to downloading, patching 58 | # and updating of the project sources are intended to be used. Also note that at 59 | # least one set of download-related arguments are required. 60 | # 61 | # If using CMake 3.2 or later, the UPDATE_DISCONNECTED option can be used to 62 | # prevent a check at the remote end for changes every time CMake is run 63 | # after the first successful download. See the documentation of the ExternalProject 64 | # module for more information. It is likely you will want to use this option if it 65 | # is available to you. Note, however, that the ExternalProject implementation contains 66 | # bugs which result in incorrect handling of the UPDATE_DISCONNECTED option when 67 | # using the URL download method or when specifying a SOURCE_DIR with no download 68 | # method. Fixes for these have been created, the last of which is scheduled for 69 | # inclusion in CMake 3.8.0. Details can be found here: 70 | # 71 | # https://gitlab.kitware.com/cmake/cmake/commit/bdca68388bd57f8302d3c1d83d691034b7ffa70c 72 | # https://gitlab.kitware.com/cmake/cmake/issues/16428 73 | # 74 | # If you experience build errors related to the update step, consider avoiding 75 | # the use of UPDATE_DISCONNECTED. 76 | # 77 | # EXAMPLE USAGE: 78 | # 79 | # include(DownloadProject) 80 | # download_project(PROJ googletest 81 | # GIT_REPOSITORY https://github.com/google/googletest.git 82 | # GIT_TAG master 83 | # UPDATE_DISCONNECTED 1 84 | # QUIET 85 | # ) 86 | # 87 | # add_subdirectory(${googletest_SOURCE_DIR} ${googletest_BINARY_DIR}) 88 | # 89 | #======================================================================================== 90 | 91 | 92 | set(_DownloadProjectDir "${CMAKE_CURRENT_LIST_DIR}") 93 | 94 | include(CMakeParseArguments) 95 | 96 | function(download_project) 97 | 98 | set(options QUIET) 99 | set(oneValueArgs 100 | PROJ 101 | PREFIX 102 | DOWNLOAD_DIR 103 | SOURCE_DIR 104 | BINARY_DIR 105 | # Prevent the following from being passed through 106 | CONFIGURE_COMMAND 107 | BUILD_COMMAND 108 | INSTALL_COMMAND 109 | TEST_COMMAND 110 | ) 111 | set(multiValueArgs "") 112 | 113 | cmake_parse_arguments(DL_ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) 114 | 115 | # Hide output if requested 116 | if (DL_ARGS_QUIET) 117 | set(OUTPUT_QUIET "OUTPUT_QUIET") 118 | else() 119 | unset(OUTPUT_QUIET) 120 | message(STATUS "Downloading/updating ${DL_ARGS_PROJ}") 121 | endif() 122 | 123 | # Set up where we will put our temporary CMakeLists.txt file and also 124 | # the base point below which the default source and binary dirs will be. 125 | # The prefix must always be an absolute path. 126 | if (NOT DL_ARGS_PREFIX) 127 | set(DL_ARGS_PREFIX "${CMAKE_BINARY_DIR}") 128 | else() 129 | get_filename_component(DL_ARGS_PREFIX "${DL_ARGS_PREFIX}" ABSOLUTE 130 | BASE_DIR "${CMAKE_CURRENT_BINARY_DIR}") 131 | endif() 132 | if (NOT DL_ARGS_DOWNLOAD_DIR) 133 | set(DL_ARGS_DOWNLOAD_DIR "${DL_ARGS_PREFIX}/${DL_ARGS_PROJ}-download") 134 | endif() 135 | 136 | # Ensure the caller can know where to find the source and build directories 137 | if (NOT DL_ARGS_SOURCE_DIR) 138 | set(DL_ARGS_SOURCE_DIR "${DL_ARGS_PREFIX}/${DL_ARGS_PROJ}-src") 139 | endif() 140 | if (NOT DL_ARGS_BINARY_DIR) 141 | set(DL_ARGS_BINARY_DIR "${DL_ARGS_PREFIX}/${DL_ARGS_PROJ}-build") 142 | endif() 143 | set(${DL_ARGS_PROJ}_SOURCE_DIR "${DL_ARGS_SOURCE_DIR}" PARENT_SCOPE) 144 | set(${DL_ARGS_PROJ}_BINARY_DIR "${DL_ARGS_BINARY_DIR}" PARENT_SCOPE) 145 | 146 | # The way that CLion manages multiple configurations, it causes a copy of 147 | # the CMakeCache.txt to be copied across due to it not expecting there to 148 | # be a project within a project. This causes the hard-coded paths in the 149 | # cache to be copied and builds to fail. To mitigate this, we simply 150 | # remove the cache if it exists before we configure the new project. It 151 | # is safe to do so because it will be re-generated. Since this is only 152 | # executed at the configure step, it should not cause additional builds or 153 | # downloads. 154 | file(REMOVE "${DL_ARGS_DOWNLOAD_DIR}/CMakeCache.txt") 155 | 156 | # Create and build a separate CMake project to carry out the download. 157 | # If we've already previously done these steps, they will not cause 158 | # anything to be updated, so extra rebuilds of the project won't occur. 159 | # Make sure to pass through CMAKE_MAKE_PROGRAM in case the main project 160 | # has this set to something not findable on the PATH. 161 | configure_file("${_DownloadProjectDir}/DownloadProject.CMakeLists.cmake.in" 162 | "${DL_ARGS_DOWNLOAD_DIR}/CMakeLists.txt") 163 | execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" 164 | -D "CMAKE_MAKE_PROGRAM:FILE=${CMAKE_MAKE_PROGRAM}" 165 | . 166 | RESULT_VARIABLE result 167 | ${OUTPUT_QUIET} 168 | WORKING_DIRECTORY "${DL_ARGS_DOWNLOAD_DIR}" 169 | ) 170 | if(result) 171 | message(FATAL_ERROR "CMake step for ${DL_ARGS_PROJ} failed: ${result}") 172 | endif() 173 | execute_process(COMMAND ${CMAKE_COMMAND} --build . 174 | RESULT_VARIABLE result 175 | ${OUTPUT_QUIET} 176 | WORKING_DIRECTORY "${DL_ARGS_DOWNLOAD_DIR}" 177 | ) 178 | if(result) 179 | message(FATAL_ERROR "Build step for ${DL_ARGS_PROJ} failed: ${result}") 180 | endif() 181 | 182 | endfunction() 183 | -------------------------------------------------------------------------------- /cmake/FindMPIR.cmake: -------------------------------------------------------------------------------- 1 | # Try to find the MPIR librairies 2 | # MPIR_FOUND - system has MPIR lib 3 | # MPIR_INCLUDE_DIR - the MPIR include directory 4 | # MPIR_LIBRARIES - Libraries needed to use MPIR 5 | 6 | # Copyright (c) 2006, Laurent Montel, 7 | # Copyright (c) 2018, Thomas Baumgart 8 | # 9 | # Redistribution and use is allowed according to the terms of the BSD license. 10 | # For details see the accompanying COPYING-CMAKE-SCRIPTS file. 11 | 12 | 13 | if (MPIR_INCLUDE_DIR AND MPIR_LIBRARIES) 14 | # Already in cache, be silent 15 | set(MPIR_FIND_QUIETLY TRUE) 16 | endif (MPIR_INCLUDE_DIR AND MPIR_LIBRARIES) 17 | 18 | find_path(MPIR_INCLUDE_DIR NAMES mpir.h ) 19 | find_library(MPIR_LIBRARIES NAMES mpir libmpir) 20 | 21 | include(FindPackageHandleStandardArgs) 22 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(MPIR DEFAULT_MSG MPIR_INCLUDE_DIR MPIR_LIBRARIES) 23 | 24 | mark_as_advanced(MPIR_INCLUDE_DIR MPIR_LIBRARIES) 25 | -------------------------------------------------------------------------------- /cmake/TMeshKernelDependencies.cmake: -------------------------------------------------------------------------------- 1 | # Prepare dependencies 2 | # 3 | # For each third-party library, if the appropriate target doesn't exist yet, 4 | # download it via external project, and add_subdirectory to build it alongside 5 | # this project. 6 | 7 | ### Configuration 8 | set(TMESH_KERNEL_ROOT "${CMAKE_CURRENT_LIST_DIR}/..") 9 | set(TMESH_KERNEL_EXTERNAL "${TMESH_KERNEL_ROOT}/external") 10 | 11 | # Download and update 3rdparty libraries 12 | list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}) 13 | list(REMOVE_DUPLICATES CMAKE_MODULE_PATH) 14 | include(TMeshKernelDownloadExternal) 15 | 16 | ################################################################################ 17 | # Required libraries 18 | ################################################################################ 19 | 20 | # Sanitizers 21 | if(TMESH_KERNEL_WITH_SANITIZERS) 22 | tmesh_kernel_download_sanitizers() 23 | find_package(Sanitizers) 24 | endif() 25 | 26 | tmesh_kernel_download_catch2() 27 | -------------------------------------------------------------------------------- /cmake/TMeshKernelDownloadExternal.cmake: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | include(DownloadProject) 3 | 4 | # With CMake 3.8 and above, we can hide warnings about git being in a 5 | # detached head by passing an extra GIT_CONFIG option 6 | if(NOT (${CMAKE_VERSION} VERSION_LESS "3.8.0")) 7 | set(TMESH_KERNEL_EXTRA_OPTIONS "GIT_CONFIG advice.detachedHead=false") 8 | else() 9 | set(TMESH_KERNEL_EXTRA_OPTIONS "") 10 | endif() 11 | 12 | # Shortcut function 13 | function(tmesh_kernel_download_project name) 14 | download_project( 15 | PROJ ${name} 16 | SOURCE_DIR ${TMESH_KERNEL_EXTERNAL}/${name} 17 | DOWNLOAD_DIR ${TMESH_KERNEL_EXTERNAL}/.cache/${name} 18 | QUIET 19 | ${TMESH_KERNEL_EXTRA_OPTIONS} 20 | ${ARGN} 21 | ) 22 | endfunction() 23 | 24 | ################################################################################ 25 | 26 | ## Catch2 BSL 1.0 27 | function(tmesh_kernel_download_catch2) 28 | tmesh_kernel_download_project(Catch2 29 | GIT_REPOSITORY https://github.com/catchorg/Catch2.git 30 | GIT_TAG v2.4.2 31 | ) 32 | endfunction() 33 | 34 | 35 | ## Sanitizers MIT 36 | function(tmesh_kernel_download_sanitizers) 37 | tmesh_kernel_download_project(sanitizers-cmake 38 | GIT_REPOSITORY https://github.com/arsenm/sanitizers-cmake.git 39 | GIT_TAG 6947cff3a9c9305eb9c16135dd81da3feb4bf87f 40 | ) 41 | endfunction() 42 | -------------------------------------------------------------------------------- /cmake/UseColors.cmake: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # When using Clang, there is nothing to do: colors are enabled by default 3 | # When using GCC >= 4.9, colored diagnostics can be enabled natively 4 | # When using an older version, one can use gccfilter (a perl script) 5 | # 6 | # I do not recommend using gccfilter as of now (May 2014), because it seems to 7 | # be bugged. But if you still want to try, here is how to install it on Ubuntu: 8 | # 9 | # 10 | # 1) Download the perl script and add it to you $PATH 11 | # mkdir -p ~/.local/bin 12 | # wget -P ~/.local/bin http://www.mixtion.org/gccfilter/gccfilter 13 | # chmod +x ~/local/bin/gccfilter 14 | # echo 'PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc 15 | # 16 | # 2) Install the dependencies 17 | # * Term::ANSIColor 18 | # sudo cpan 19 | # cpan> install Term::ANSIColor 20 | # * The module "Getopt::Long" is included in "perl-base" 21 | # * For Getopt::ArgvFile and Regexp::Common ... 22 | # sudo apt-get install libgetopt-argvfile-perl libregexp-common-perl 23 | # 24 | ################################################################################ 25 | 26 | if(CMAKE_COMPILER_IS_GNUCXX) 27 | # If GCC >= 4.9, just activate the right option 28 | # We enable colorized diagnostics always instead of using "auto" so that 29 | # they're still colored when using Ninja. 30 | if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9) 31 | message(STATUS "GCC >= 4.9 detected, enabling colored diagnostics") 32 | add_definitions(-fdiagnostics-color=always) 33 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdiagnostics-color=always") 34 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fdiagnostics-color=always") 35 | return() 36 | endif() 37 | # If GCC < 4.9, maybe we can use gccfilter 38 | find_program(GCC_FILTER gccfilter) 39 | if(GCC_FILTER) 40 | option(COLOR_GCC "Use GCCFilter to color compiler output messages" OFF) 41 | set(COLOR_GCC_OPTIONS "-c -r -w" CACHE STRING "Arguments that are passed to gccfilter when output coloring is switchend on. Defaults to -c -r -w.") 42 | if(COLOR_GCC) 43 | set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${GCC_FILTER} ${COLOR_GCC_OPTIONS}") 44 | message(STATUS "Using gccfilter for colored diagnostics") 45 | endif() 46 | endif() 47 | endif() 48 | -------------------------------------------------------------------------------- /cmake/Warnings.cmake: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | cmake_minimum_required(VERSION 2.6.3) 3 | ################################################################################ 4 | # See comments and discussions here: 5 | # http://stackoverflow.com/questions/5088460/flags-to-enable-thorough-and-verbose-g-warnings 6 | ################################################################################ 7 | 8 | if(TARGET warnings::all) 9 | return() 10 | endif() 11 | 12 | set(MY_FLAGS 13 | -Wall 14 | -Wextra 15 | -pedantic 16 | 17 | # -Wconversion 18 | #-Wunsafe-loop-optimizations # broken with C++11 loops 19 | -Wunused 20 | 21 | -Wno-long-long 22 | -Wpointer-arith 23 | -Wformat=2 24 | -Wuninitialized 25 | -Wcast-qual 26 | -Wmissing-noreturn 27 | -Wmissing-format-attribute 28 | -Wredundant-decls 29 | 30 | -Werror=implicit 31 | -Werror=nonnull 32 | -Werror=init-self 33 | -Werror=main 34 | -Werror=missing-braces 35 | -Werror=sequence-point 36 | -Werror=return-type 37 | -Werror=trigraphs 38 | -Werror=array-bounds 39 | -Werror=write-strings 40 | -Werror=address 41 | -Werror=int-to-pointer-cast 42 | -Werror=pointer-to-int-cast 43 | 44 | -Wno-unused-variable 45 | -Wunused-but-set-variable 46 | -Wno-unused-parameter 47 | 48 | #-Weffc++ 49 | -Wno-old-style-cast 50 | # -Wno-sign-conversion 51 | #-Wsign-conversion 52 | 53 | -Wshadow 54 | 55 | -Wstrict-null-sentinel 56 | -Woverloaded-virtual 57 | -Wsign-promo 58 | -Wstack-protector 59 | -Wstrict-aliasing 60 | -Wstrict-aliasing=2 61 | -Wswitch-default 62 | -Wswitch-enum 63 | -Wswitch-unreachable 64 | 65 | -Wcast-align 66 | -Wdisabled-optimization 67 | #-Winline # produces warning on default implicit destructor 68 | -Winvalid-pch 69 | # -Wmissing-include-dirs 70 | -Wpacked 71 | -Wno-padded 72 | -Wstrict-overflow 73 | -Wstrict-overflow=2 74 | 75 | -Wctor-dtor-privacy 76 | -Wlogical-op 77 | -Wnoexcept 78 | -Woverloaded-virtual 79 | # -Wundef 80 | 81 | -Wnon-virtual-dtor 82 | -Wdelete-non-virtual-dtor 83 | -Werror=non-virtual-dtor 84 | -Werror=delete-non-virtual-dtor 85 | 86 | -Wno-sign-compare 87 | 88 | ########### 89 | # GCC 6.1 # 90 | ########### 91 | 92 | -Wnull-dereference 93 | -fdelete-null-pointer-checks 94 | -Wduplicated-cond 95 | -Wmisleading-indentation 96 | 97 | #-Weverything 98 | 99 | ########################### 100 | # Enabled by -Weverything # 101 | ########################### 102 | 103 | #-Wdocumentation 104 | #-Wdocumentation-unknown-command 105 | #-Wfloat-equal 106 | #-Wcovered-switch-default 107 | 108 | #-Wglobal-constructors 109 | #-Wexit-time-destructors 110 | #-Wmissing-variable-declarations 111 | #-Wextra-semi 112 | #-Wweak-vtables 113 | #-Wno-source-uses-openmp 114 | #-Wdeprecated 115 | #-Wnewline-eof 116 | #-Wmissing-prototypes 117 | 118 | #-Wno-c++98-compat 119 | #-Wno-c++98-compat-pedantic 120 | 121 | ########################### 122 | # Need to check if those are still valid today 123 | ########################### 124 | 125 | #-Wimplicit-atomic-properties 126 | #-Wmissing-declarations 127 | #-Wmissing-prototypes 128 | #-Wstrict-selector-match 129 | #-Wundeclared-selector 130 | #-Wunreachable-code 131 | 132 | # Not a warning, but enable link-time-optimization 133 | # TODO: Check out modern CMake version of setting this flag 134 | # https://cmake.org/cmake/help/latest/module/CheckIPOSupported.html 135 | #-flto 136 | 137 | # Gives meaningful stack traces 138 | -fno-omit-frame-pointer 139 | -fno-optimize-sibling-calls 140 | ) 141 | 142 | # Flags above don't make sense for MSVC 143 | if(MSVC) 144 | set(MY_FLAGS) 145 | endif() 146 | 147 | include(CheckCXXCompilerFlag) 148 | 149 | add_library(warnings_all INTERFACE) 150 | add_library(warnings::all ALIAS warnings_all) 151 | 152 | foreach(FLAG IN ITEMS ${MY_FLAGS}) 153 | string(REPLACE "=" "-" FLAG_VAR "${FLAG}") 154 | if(NOT DEFINED IS_SUPPORTED_${FLAG_VAR}) 155 | check_cxx_compiler_flag("${FLAG}" IS_SUPPORTED_${FLAG_VAR}) 156 | endif() 157 | if(IS_SUPPORTED_${FLAG_VAR}) 158 | target_compile_options(warnings_all INTERFACE ${FLAG}) 159 | endif() 160 | endforeach() 161 | -------------------------------------------------------------------------------- /cmake/mpir.cmake: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # Find MPIR and build it as part of the current build 3 | ################################################################################ 4 | 5 | if(TARGET mpir) 6 | return() 7 | endif() 8 | 9 | ################################################################################ 10 | 11 | 12 | add_library(mpir INTERFACE) 13 | 14 | if(${CMAKE_SYSTEM_NAME} MATCHES "Windows") 15 | target_include_directories(mpir INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/mpir) 16 | 17 | if(${TMESH_KERNEL_IS_Pentium_4_SSE2}) 18 | target_link_libraries(mpir INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/mpir/mpir32.lib) 19 | elseif(${TMESH_KERNEL_IS_intel_core2}) 20 | target_link_libraries(mpir INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/mpir/mpir64.lib) 21 | elseif(CMAKE_SIZEOF_VOID_P EQUAL 8) 22 | target_link_libraries(mpir INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/mpir/mpir64-generic.lib) 23 | else() 24 | target_link_libraries(mpir INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/mpir/mpir32-generic.lib) 25 | endif() 26 | elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux") 27 | if(${TMESH_KERNEL_USE_MPIR_PROVIDED_BINARY}) 28 | target_include_directories(mpir INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/mpir) 29 | target_link_libraries(mpir INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/mpir/libmpir.a) 30 | else() 31 | find_package(MPIR) 32 | 33 | if(NOT ${MPIR_FOUND}) 34 | MESSAGE(FATAL_ERROR "Unable to find mpir") 35 | endif() 36 | 37 | target_include_directories(mpir INTERFACE ${MPIR_INCLUDE_DIR}) 38 | target_link_libraries(mpir INTERFACE ${MPIR_LIBRARIES}) 39 | endif() 40 | elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") 41 | find_package(MPIR) 42 | 43 | if(NOT ${MPIR_FOUND}) 44 | MESSAGE(FATAL_ERROR "Unable to find mpir") 45 | endif() 46 | 47 | target_include_directories(mpir INTERFACE ${MPIR_INCLUDE_DIR}) 48 | target_link_libraries(mpir INTERFACE ${MPIR_LIBRARIES}) 49 | endif() 50 | 51 | -------------------------------------------------------------------------------- /include/basics.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * basics.h * 3 | * This file is part of the TMesh_Kernel Library * 4 | * * 5 | * Authors: Marco Attene * 6 | * Copyright(C) 2012: IMATI-GE / CNR * 7 | * IMATI-GE / CNR is Consiglio Nazionale delle Ricerche * 8 | * Istituto di Matematica Applicata e Tecnologie Informatiche * 9 | * Genova (Italy) * 10 | * * 11 | * TMesh_Kernel is free software; you can redistribute it and/or modify * 12 | * it under the terms of the GNU Lesser General Public License as published * 13 | * by the Free Software Foundation; either version 3 of the License, or (at * 14 | * your option) any later version. * 15 | * * 16 | * TMesh_Kernel is distributed in the hope that it will be useful, but * 17 | * WITHOUT ANY WARRANTY; without even the implied warranty of * 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser * 19 | * General Public License for more details. * 20 | * * 21 | * You should have received a copy of the GNU Lesser General Public License * 22 | * along with TMesh_Kernel. If not, see http://www.gnu.org/licenses/. * 23 | * * 24 | ****************************************************************************/ 25 | 26 | #ifndef _BASICS_H 27 | #define _BASICS_H 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include "coordinates.h" 35 | #include 36 | 37 | namespace T_MESH 38 | { 39 | 40 | #ifdef EXTENSIBLE_TMESH 41 | #define TMESH_VIRTUAL virtual 42 | #else 43 | #define TMESH_VIRTUAL 44 | #endif 45 | 46 | #ifndef M_PI 47 | #define M_PI 3.14159265358979323846 48 | #endif 49 | 50 | #define DISPMSG_ACTION_SETWIDGET 1 51 | #define DISPMSG_ACTION_PUTNEWLINE 2 52 | #define DISPMSG_ACTION_PUTPROGRESS 3 53 | #define DISPMSG_ACTION_PUTMESSAGE 4 54 | #define DISPMSG_ACTION_ERRORDIALOG 5 55 | 56 | typedef unsigned char UBYTE; 57 | typedef signed char BYTE; 58 | #ifndef _INC_WINDOWS 59 | typedef unsigned short UINT16; 60 | typedef signed short INT16; 61 | #endif 62 | 63 | #if defined (IS64BITPLATFORM) || defined(_WIN64) || defined(__x86_64__) || defined(__ppc64__) 64 | typedef int64_t j_voidint; 65 | #else 66 | typedef int32_t j_voidint; 67 | #endif 68 | 69 | 70 | #define FABS(a) (((a)<0)?(-(a)):(a)) 71 | #define LOG2(a) (log(a)/log(2)) 72 | #define PI2 (M_PI/2.0) 73 | 74 | #ifndef MIN 75 | #define MIN(a,b) (((a)<(b))?(a):(b)) 76 | #endif 77 | 78 | #ifndef MAX 79 | #define MAX(a,b) (((a)>(b))?(a):(b)) 80 | #endif 81 | 82 | 83 | //////// Swaps two pointers. /////////////////////////////// 84 | 85 | inline void p_swap(void **a, void **b) { void *t = *a; *a = *b; *b = t; } 86 | 87 | ///////////////////////////////////////////////////////////////////////////////////////////// 88 | 89 | 90 | #define TMESH_VERSION "5.0" 91 | #define TMESH_YEAR 2019 92 | 93 | 94 | struct thread_initializer 95 | { 96 | explicit thread_initializer() {} 97 | 98 | //Copy constructor that does the init 99 | thread_initializer(thread_initializer& _it) 100 | { 101 | #ifdef USE_HYBRID_KERNEL 102 | setFPUModeToRoundUP(); 103 | #endif 104 | } 105 | }; 106 | 107 | extern thread_initializer tmesh_thread_initializer; 108 | 109 | class TMesh 110 | { 111 | public: 112 | 113 | static void (*display_message)(const char *, int); 114 | static char *app_name; 115 | static char *app_version; 116 | static char *app_year; 117 | static char *app_authors; 118 | static char *app_url; 119 | static char *app_maillist; 120 | 121 | static const char *filename; // This might be null. If not, it represents the file we are currently working with. 122 | 123 | static bool quiet; 124 | 125 | static void init(void (*)(const char *, int) = NULL); 126 | 127 | static void info(const char *, ...); 128 | static void warning(const char *, ...); 129 | static void error(const char *, ...); 130 | static void begin_progress(); 131 | static void report_progress(const char *, ...); 132 | static void end_progress(); 133 | 134 | //! When called with a nonzero argument 'ts', launches a chronometer with a timeout of 'ts' seconds. 135 | //! Later calls without arguments check the chronometer, and if it is over 'ts' the program exits. 136 | static void exitOnTimeout(clock_t ts = 0); 137 | 138 | //! Appends a line to the file "tmesh.log" 139 | static void addMessageToLogFile(const char *msg); 140 | 141 | //! Formats a message headed with date/time/filename, appends it to "tmesh.log", and exits with error 142 | static void logToFileAndExit(const char *msg); 143 | 144 | //! When called without arguments prints the elapsed time from the latest reset. 145 | static void printElapsedTime(bool reset = false); 146 | 147 | //! Turn and check the use of rational arithmetic 148 | static void useRationals(bool u); 149 | static bool isUsingRationals(); 150 | 151 | //! Swith to exact arithmetic and return the status before the switch 152 | static bool useRationals() { bool t = isUsingRationals(); useRationals(true); return t; } 153 | 154 | //! Set the working project's filename 155 | static void setFilename(const char *fname) { filename = fname; } 156 | 157 | static double tri_orientation(double *pa, double *pb, double *pc); 158 | static double tet_orientation(double *pa, double *pb, double *pc, double *pd); 159 | static double insphere(double *pa, double *pb, double *pc, double *pd, double *pe); 160 | static double incircle3D(double *pa, double *pb, double *pc, double *pd); 161 | }; 162 | 163 | } //namespace T_MESH 164 | 165 | #endif //_BASICS_H 166 | 167 | -------------------------------------------------------------------------------- /include/coordinates.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * coordinates.h * 3 | * This file is part of the TMesh_Kernel Library * 4 | * * 5 | * Authors: Marco Attene * 6 | * Copyright(C) 2012: IMATI-GE / CNR * 7 | * IMATI-GE / CNR is Consiglio Nazionale delle Ricerche * 8 | * Istituto di Matematica Applicata e Tecnologie Informatiche * 9 | * Genova (Italy) * 10 | * * 11 | * TMesh_Kernel is free software; you can redistribute it and/or modify * 12 | * it under the terms of the GNU Lesser General Public License as published * 13 | * by the Free Software Foundation; either version 3 of the License, or (at * 14 | * your option) any later version. * 15 | * * 16 | * TMesh_Kernel is distributed in the hope that it will be useful, but * 17 | * WITHOUT ANY WARRANTY; without even the implied warranty of * 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser * 19 | * General Public License for more details. * 20 | * * 21 | * You should have received a copy of the GNU Lesser General Public License * 22 | * along with TMesh_Kernel. If not, see http://www.gnu.org/licenses/. * 23 | * * 24 | ****************************************************************************/ 25 | 26 | #ifndef _COORDINATES_H 27 | #define _COORDINATES_H 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | namespace T_MESH 35 | { 36 | 37 | #define TMESH_NAN NAN 38 | #define TMESH_INFINITY INFINITY 39 | 40 | // This is the maximum value that can be represented in all the possible configurations 41 | #define TMESH_MAX_COORDINATE DBL_MAX 42 | 43 | #ifdef WIN32 44 | typedef unsigned int fpu_status_t; 45 | inline fpu_status_t getFPURoundingMode() { return _controlfp(0, 0); } 46 | inline void setFPU53BitsPrecision() { _control87(_PC_53, _MCW_PC); } 47 | inline void setFPURoundingMode(fpu_status_t r) { _controlfp(r, _MCW_RC); } 48 | inline void setFPUModeToRoundUP() { _controlfp(_RC_UP, _MCW_RC); } 49 | inline void setFPUModeToRoundNEAR() { _controlfp(_RC_NEAR, _MCW_RC); } 50 | #else 51 | } 52 | 53 | #include 54 | #if __APPLE__ 55 | #define _FPU_SETCW(cw) // nothing https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/float.3.html 56 | #else 57 | #include 58 | #endif 59 | 60 | namespace T_MESH 61 | { 62 | typedef int fpu_status_t; 63 | inline fpu_status_t getFPURoundingMode() { return fegetround(); } 64 | inline void setFPU53BitsPrecision() { int cw = 4722; _FPU_SETCW(cw); } 65 | inline void setFPURoundingMode(fpu_status_t r) { fesetround(r); } 66 | inline void setFPUModeToRoundUP() { fesetround(FE_UPWARD); } 67 | inline void setFPUModeToRoundNEAR() { fesetround(FE_TONEAREST); } 68 | 69 | #endif 70 | } 71 | 72 | #ifdef WIN32 73 | #pragma warning( disable : 4756) 74 | #endif 75 | 76 | #ifdef USE_HYBRID_KERNEL 77 | 78 | #ifdef WIN32 79 | #pragma warning( disable : 4056) 80 | #pragma warning( disable : 4146) 81 | #pragma warning( disable : 4800) 82 | #endif 83 | 84 | #include 85 | 86 | #include 87 | namespace T_MESH 88 | { 89 | // Use the following to filter out sign and mantissa 90 | #define EXPONENT_MASK 0x7FF0000000000000L 91 | 92 | // Use the following to filter out sign and exponent 93 | #define MANTISSA_MASK 0x000FFFFFFFFFFFFFL 94 | 95 | //This is 2^(-52) << 52 96 | #define MACH_DIFFEPS 0x0340000000000000L 97 | 98 | // Interpret 64 bits as either a double or a uint64_t 99 | // Useful to quickly play with bits in IEEE 754 standard representation 100 | typedef union error_approx_type_t 101 | { 102 | double d; 103 | uint64_t u; 104 | 105 | inline error_approx_type_t() {} 106 | inline error_approx_type_t(double a) : d(a) {} 107 | inline uint64_t is_negative() const { return u >> 63; } 108 | inline bool is_finite() const { return ((u & EXPONENT_MASK) != EXPONENT_MASK); } 109 | inline bool is_nan() const { return (u & MANTISSA_MASK); } 110 | } casted_double; 111 | 112 | // tmesh_fraction is essentially the same as mpq_class, but it correctly implements 113 | // the semantics of NaNs and Infinities as specified in IEEE 754 standard. 114 | // A more efficient solution is possible by tweaking mpir directly, 115 | // but this solution would require a fork to mpir which becomes tricky to update. 116 | // Hopefully, future versions of mpir will correctly handle these cases. 117 | // If and when this will happen, tmesh_fraction should be easily replaceable with 118 | // mpq_class. 119 | 120 | class tmesh_fraction 121 | { 122 | private: 123 | mpq_t mp; 124 | 125 | // Quick zero-check for mpz numbers 126 | static inline int is_mpz_zero(const __mpz_struct& z) { return (!z._mp_size); } 127 | 128 | // TRUE if mpq is NAN or INFINITY 129 | static inline bool is_nan_or_infinity(const mpq_t& op) { return is_mpz_zero(op->_mp_den); } 130 | 131 | // TRUE if mpq is ZERO 132 | static inline bool is_zero(const mpq_t& op) { return is_mpz_zero(op->_mp_num); } 133 | 134 | // TRUE if either arg is NAN or INFINITY 135 | static inline bool nan_or_infinity_ops(const mpq_t& op1, const mpq_t& op2) { return (is_nan_or_infinity(op1) || is_nan_or_infinity(op2)); } 136 | 137 | // TRUE if op is NAN 138 | static inline bool is_nan(const mpq_t& op) { return (is_mpz_zero(op->_mp_num) && is_mpz_zero(op->_mp_den)); } 139 | 140 | // TRUE if op is INFINITY 141 | static inline bool is_infinity(const mpq_t& op) { return (!is_mpz_zero(op->_mp_num) && is_mpz_zero(op->_mp_den)); } 142 | 143 | // TRUE if op is POSITIVE INFINITY 144 | static inline bool is_plus_infinity(const mpq_t& op) { return ((op->_mp_num._mp_size > 0) && is_mpz_zero(op->_mp_den)); } 145 | 146 | // TRUE if op is NEGATIVE INFINITY 147 | static inline bool is_minus_infinity(const mpq_t& op) { return ((op->_mp_num._mp_size < 0) && is_mpz_zero(op->_mp_den)); } 148 | 149 | // TRUE if op is POSITIVE (including infinity) 150 | static inline bool is_positive(const mpq_t& op) { return (op->_mp_num._mp_size > 0); } 151 | 152 | // TRUE if op is NEGATIVE (including infinity) 153 | static inline bool is_negative(const mpq_t& op) { return (op->_mp_num._mp_size < 0); } 154 | 155 | 156 | public: 157 | inline tmesh_fraction() { mpq_init(mp); } 158 | inline tmesh_fraction(const tmesh_fraction& a) { mpq_init(mp); mpq_set(mp, a.mp); } 159 | inline tmesh_fraction(mpq_srcptr q) { mpq_init(mp); mpq_set(mp, q); } 160 | inline tmesh_fraction(const mpz_srcptr &d) { mpq_init(mp); mpz_set(mpq_numref(mp), d); mpz_set_ui(mpq_denref(mp), 1); } 161 | inline tmesh_fraction(const mpz_srcptr &num, const mpz_srcptr &den) { mpq_init(mp); mpz_set(mpq_numref(mp), num); mpz_set(mpq_denref(mp), den); } 162 | inline tmesh_fraction(double a) 163 | { 164 | mpq_init(mp); 165 | casted_double d(a); 166 | if (d.is_finite()) mpq_set_d(mp, a); 167 | else if (d.is_nan()) setAsNAN(); 168 | else if (d.is_negative()) setAsMinusInfinity(); 169 | else setAsPlusInfinity(); 170 | } 171 | 172 | inline void setAsNAN() { mpz_set_ui(mpq_numref(mp), 0); mpz_set_ui(mpq_denref(mp), 0); } 173 | inline void setAsPlusInfinity() { mpz_set_ui(mpq_numref(mp), 1); mpz_set_ui(mpq_denref(mp), 0); } 174 | inline void setAsMinusInfinity() { mpz_set_si(mpq_numref(mp), -1); mpz_set_ui(mpq_denref(mp), 0); } 175 | 176 | const mpq_t& get_mpq_t() const { return mp; } 177 | 178 | inline double get_d() const { return mpq_get_d(mp); } 179 | 180 | inline const mpz_srcptr get_den() const { return &mp->_mp_den; } 181 | inline const mpz_srcptr get_num() const { return &mp->_mp_num; } 182 | 183 | inline tmesh_fraction operator+(const tmesh_fraction& b) const 184 | { 185 | tmesh_fraction r; 186 | if (nan_or_infinity_ops(mp, b.mp)) 187 | { 188 | if (is_nan(mp) || is_nan(b.mp) || (is_plus_infinity(mp) && is_minus_infinity(b.mp)) || (is_plus_infinity(b.mp) && is_minus_infinity(mp))) { r.setAsNAN(); return r; } 189 | if (is_plus_infinity(mp) || is_plus_infinity(b.mp)) { r.setAsPlusInfinity(); return r; } 190 | if (is_minus_infinity(mp) || is_minus_infinity(b.mp)) { r.setAsMinusInfinity(); return r; } 191 | } 192 | mpq_add(r.mp, mp, b.mp); 193 | return r; 194 | } 195 | 196 | inline tmesh_fraction operator-(const tmesh_fraction& b) const 197 | { 198 | tmesh_fraction r; 199 | if (nan_or_infinity_ops(mp, b.mp)) 200 | { 201 | if (is_nan(mp) || is_nan(b.mp) || (is_plus_infinity(mp) && is_plus_infinity(b.mp)) || (is_minus_infinity(b.mp) && is_minus_infinity(mp))) { r.setAsNAN(); return r; } 202 | if (is_plus_infinity(mp) || is_minus_infinity(b.mp)) { r.setAsPlusInfinity(); return r; } 203 | if (is_minus_infinity(mp) || is_plus_infinity(b.mp)) { r.setAsMinusInfinity(); return r; } 204 | } 205 | mpq_sub(r.mp, mp, b.mp); 206 | return r; 207 | } 208 | 209 | inline tmesh_fraction operator*(const tmesh_fraction& b) const 210 | { 211 | tmesh_fraction r; 212 | if (nan_or_infinity_ops(mp, b.mp)) 213 | { 214 | if (is_nan(mp) || is_nan(b.mp) || (is_infinity(mp) && is_zero(b.mp)) || (is_infinity(b.mp) && is_zero(mp))) { r.setAsNAN(); return r; } 215 | if ((is_negative(mp) && is_negative(b.mp)) || (is_positive(mp) && is_positive(b.mp))) { r.setAsPlusInfinity(); return r; } 216 | if ((is_negative(mp) && is_positive(b.mp)) || (is_positive(mp) && is_negative(b.mp))) { r.setAsMinusInfinity(); return r; } 217 | } 218 | mpq_mul(r.mp, mp, b.mp); 219 | return r; 220 | } 221 | 222 | inline tmesh_fraction operator/(const tmesh_fraction& b) const 223 | { 224 | tmesh_fraction r; 225 | if (nan_or_infinity_ops(mp, b.mp) || is_zero(b.mp)) 226 | { 227 | if (is_nan(mp) || is_nan(b.mp) || (is_zero(mp) && is_zero(b.mp)) || (is_infinity(b.mp) && is_infinity(mp))) { r.setAsNAN(); return r; } 228 | if (is_infinity(b.mp)) { return r; } 229 | if (is_positive(mp)) { r.setAsPlusInfinity(); return r; } 230 | if (is_negative(mp)) { r.setAsMinusInfinity(); return r; } 231 | } 232 | mpq_div(r.mp, mp, b.mp); 233 | return r; 234 | } 235 | 236 | inline tmesh_fraction& operator+=(const tmesh_fraction& b) 237 | { 238 | tmesh_fraction r = (*this) + (b); 239 | mpq_set(mp, r.mp); 240 | return *this; 241 | } 242 | 243 | inline tmesh_fraction& operator-=(const tmesh_fraction& b) 244 | { 245 | tmesh_fraction r = (*this) - (b); 246 | mpq_set(mp, r.mp); 247 | return *this; 248 | } 249 | 250 | inline tmesh_fraction& operator*=(const tmesh_fraction& b) 251 | { 252 | tmesh_fraction r = (*this) * (b); 253 | mpq_set(mp, r.mp); 254 | return *this; 255 | } 256 | 257 | inline tmesh_fraction& operator/=(const tmesh_fraction& b) 258 | { 259 | tmesh_fraction r = (*this) / (b); 260 | mpq_set(mp, r.mp); 261 | return *this; 262 | } 263 | 264 | inline bool operator==(const tmesh_fraction& b) const { 265 | if (nan_or_infinity_ops(mp, b.mp)) 266 | { 267 | return ((is_plus_infinity(mp) && is_plus_infinity(b.mp)) || (is_minus_infinity(mp) && is_minus_infinity(b.mp))); 268 | } 269 | return mpq_equal(mp, b.mp); 270 | } 271 | inline bool operator!=(const tmesh_fraction& b) const { 272 | if (nan_or_infinity_ops(mp, b.mp)) 273 | { 274 | return (!((is_plus_infinity(mp) && is_plus_infinity(b.mp)) || (is_minus_infinity(mp) && is_minus_infinity(b.mp)))); 275 | } 276 | return !mpq_equal(mp, b.mp); 277 | } 278 | inline bool operator<(const tmesh_fraction& b) const { 279 | if (nan_or_infinity_ops(mp, b.mp)) 280 | { 281 | if (is_nan(mp) || is_nan(b.mp)) return false; 282 | return ((is_plus_infinity(b.mp) && !is_plus_infinity(mp)) || ((is_minus_infinity(mp) && !is_minus_infinity(b.mp)))); 283 | } 284 | return (mpq_cmp(mp, b.mp)<0); 285 | } 286 | inline bool operator>(const tmesh_fraction& b) const { 287 | if (nan_or_infinity_ops(mp, b.mp)) 288 | { 289 | if (is_nan(mp) || is_nan(b.mp)) return false; 290 | return ((is_plus_infinity(mp) && !is_plus_infinity(b.mp)) || ((is_minus_infinity(b.mp) && !is_minus_infinity(mp)))); 291 | } 292 | return (mpq_cmp(mp, b.mp)>0); 293 | } 294 | inline bool operator<=(const tmesh_fraction& b) const { 295 | if (nan_or_infinity_ops(mp, b.mp)) 296 | { 297 | if (is_nan(mp) || is_nan(b.mp)) return false; 298 | return (is_plus_infinity(b.mp) || is_minus_infinity(mp)); 299 | } 300 | return (mpq_cmp(mp, b.mp) <= 0); 301 | } 302 | inline bool operator>=(const tmesh_fraction& b) const { 303 | if (nan_or_infinity_ops(mp, b.mp)) 304 | { 305 | if (is_nan(mp) || is_nan(b.mp)) return false; 306 | return (is_plus_infinity(mp) || is_minus_infinity(b.mp)); 307 | } 308 | return (mpq_cmp(mp, b.mp) >= 0); 309 | } 310 | 311 | inline bool operator==(int b) const { return (!is_nan_or_infinity(mp) && (mpq_cmp_si(mp, b, 1) == 0)); } 312 | 313 | inline bool operator!=(int b) const { return (is_nan_or_infinity(mp) || (mpq_cmp_si(mp, b, 1) != 0)); } 314 | 315 | inline bool operator<(int b) const { 316 | if (is_nan_or_infinity(mp)) return is_minus_infinity(mp); 317 | return (mpq_cmp_si(mp, b, 1) < 0); 318 | } 319 | inline bool operator>(int b) const { 320 | if (is_nan_or_infinity(mp)) return is_plus_infinity(mp); 321 | return (mpq_cmp_si(mp, b, 1) > 0); 322 | } 323 | inline bool operator<=(int b) const { 324 | if (is_nan_or_infinity(mp)) return is_minus_infinity(mp); 325 | return (mpq_cmp_si(mp, b, 1) <= 0); 326 | } 327 | inline bool operator>=(int b) const { 328 | if (is_nan_or_infinity(mp)) return is_plus_infinity(mp); 329 | return (mpq_cmp_si(mp, b, 1) >= 0); 330 | } 331 | 332 | inline int sign() const { return mpq_sgn(mp); } 333 | }; 334 | 335 | inline int sgn(const tmesh_fraction& f) { return f.sign(); } 336 | } 337 | 338 | #ifdef USE_LAZY_KERNEL 339 | #include "unprecise_numbers.h" 340 | 341 | typedef T_MESH::lazy_num EXACT_NT; 342 | #define EXACT_NT_FRACTION(x) ((x)->exact()) 343 | #define EXACT_NT_SIGN(x) ((x).sign()) 344 | #define EXACT_NT_TO_DOUBLE(x) ((x).approx()) 345 | #define EXACT_NT_DENOMINATOR(x) ((x)->exact().get_den()) 346 | #define EXACT_NT_NUMERATOR(x) ((x)->exact().get_num()) 347 | #define EXACT_NT_NAN EXACT_NT(TMESH_NAN) 348 | #define EXACT_NT_FPUT(x,f) ((x)->fput((f))) 349 | #define EXACT_NT_FGET(x,f) ((x)->fget((f))) 350 | 351 | #else 352 | 353 | namespace T_MESH 354 | { 355 | typedef tmesh_fraction EXACT_NT; 356 | } 357 | 358 | #define EXACT_NT_FRACTION(x) (*(x)) 359 | #define EXACT_NT_SIGN(x) (sgn(x)) 360 | #define EXACT_NT_TO_DOUBLE(x) ((x).get_d()) 361 | #define EXACT_NT_DENOMINATOR(x) ((x)->get_den()) 362 | #define EXACT_NT_NUMERATOR(x) ((x)->get_num()) 363 | #define EXACT_NT_NAN EXACT_NT(0, 0) 364 | #define EXACT_NT_FPUT(x,f) gmp_fprintf((f), "%Qd", (x)->get_mpq_t()) 365 | #define EXACT_NT_FGET(x,f) gmp_fscanf((f), "%Qd", (x)->get_mpq_t()) 366 | 367 | #endif // USE_LAZY_KERNEL 368 | 369 | #endif // USE_HYBRID_KERNEL 370 | 371 | 372 | namespace T_MESH 373 | { 374 | 375 | #ifdef USE_HYBRID_KERNEL 376 | 377 | double to_upper_double(const tmesh_fraction& a); 378 | double to_lower_double(const tmesh_fraction& a); 379 | 380 | class PM_Rational 381 | { 382 | // This represents the current kernel precision (TRUE=exact, FALSE=approximated) 383 | public: 384 | #ifdef WIN32 385 | static __declspec(thread) char use_rationals; 386 | #else 387 | static thread_local char use_rationals; 388 | #endif 389 | 390 | inline static bool isUsingRationals() { return use_rationals; } 391 | inline static void useRationals(bool v) { use_rationals = v; } 392 | 393 | protected: 394 | double _val_d; // Double version. Always present. 395 | EXACT_NT *_val_p; // Exact version. If NULL, this number is meant to represent a double 396 | 397 | inline EXACT_NT& getVal() { return *_val_p; } // Exact value 398 | inline const EXACT_NT& getVal() const { return *_val_p; } 399 | 400 | inline double& getDVal() { return _val_d; } // Double value 401 | inline const double& getDVal() const { return _val_d; } 402 | 403 | // Switch to rational 404 | inline void S2RF() { _val_p = new EXACT_NT(_val_d); } // If known to be not already rational 405 | inline void S2R() { if (!_val_p) S2RF(); } // With the check 406 | 407 | 408 | public: 409 | inline PM_Rational() : _val_p(NULL) {} // Undetermined double 410 | inline PM_Rational(const EXACT_NT& a) : _val_d(EXACT_NT_TO_DOUBLE(a)), _val_p(new EXACT_NT(a)) { } 411 | inline PM_Rational(float a) : _val_d(a), _val_p(NULL) { } 412 | inline PM_Rational(double a) : _val_d(a), _val_p(NULL) { } 413 | inline PM_Rational(int a) : _val_d(a), _val_p(NULL) { } 414 | inline PM_Rational(const PM_Rational& a) : _val_d(a._val_d) { if (a._val_p) _val_p = new EXACT_NT(*a._val_p); else _val_p = NULL; } 415 | 416 | inline ~PM_Rational() { if (_val_p) delete (_val_p); } 417 | 418 | inline EXACT_NT toRational() const { return (_val_p) ? (*_val_p) : (EXACT_NT(_val_d)); } 419 | 420 | inline bool isOfRationalType() const { return _val_p; } 421 | inline bool isOfDoubleType() const { return !_val_p; } 422 | 423 | inline int sign() const { return (_val_p) ? (EXACT_NT_SIGN((*_val_p))) : ((_val_d > 0) - (_val_d < 0)); } 424 | 425 | inline double toDouble() const { return _val_d; } 426 | inline int toInt() const { return int(toDouble()); } 427 | inline float toFloat() const { return float(toDouble()); } 428 | 429 | inline double toNearestDouble() const { return (_val_p) ? ((EXACT_NT_FRACTION(_val_p)).get_d()) : (_val_d); } 430 | inline double toUpperDouble() const { return (_val_p) ? (to_upper_double(EXACT_NT_FRACTION(_val_p))) : (_val_d); } 431 | inline double toLowerDouble() const { return (_val_p) ? (to_lower_double(EXACT_NT_FRACTION(_val_p))) : (_val_d); } 432 | 433 | inline void operator+=(const PM_Rational& a) 434 | { 435 | if (use_rationals) { S2R(); (*(_val_p)) += a.toRational(); } 436 | _val_d += a.toDouble(); 437 | } 438 | 439 | inline void operator-=(const PM_Rational& a) 440 | { 441 | if (use_rationals) { S2R(); (*(_val_p)) -= a.toRational(); } 442 | _val_d -= a.toDouble(); 443 | } 444 | 445 | inline void operator*=(const PM_Rational& a) 446 | { 447 | if (use_rationals) { S2R(); (*(_val_p)) *= a.toRational(); } 448 | _val_d *= a.toDouble(); 449 | } 450 | 451 | inline void operator/=(const PM_Rational& a) 452 | { 453 | if (use_rationals) { S2R(); (*(_val_p)) /= a.toRational(); } 454 | _val_d /= a.toDouble(); 455 | } 456 | 457 | inline PM_Rational operator+(const PM_Rational& a) const 458 | { 459 | if (use_rationals) return PM_Rational(toRational() + a.toRational()); 460 | return PM_Rational(toDouble() + a.toDouble()); 461 | } 462 | 463 | inline PM_Rational operator-(const PM_Rational& a) const 464 | { 465 | if (use_rationals) return PM_Rational(toRational() - a.toRational()); 466 | return PM_Rational(toDouble() - a.toDouble()); 467 | } 468 | 469 | inline PM_Rational operator*(const PM_Rational& a) const 470 | { 471 | if (use_rationals) return PM_Rational(toRational() * a.toRational()); 472 | return PM_Rational(toDouble() * a.toDouble()); 473 | } 474 | 475 | inline PM_Rational operator/(const PM_Rational& a) const 476 | { 477 | if (use_rationals) return PM_Rational(toRational() / a.toRational()); 478 | return PM_Rational(toDouble() / a.toDouble()); 479 | } 480 | 481 | inline bool operator==(const PM_Rational& a) const 482 | { 483 | if (_val_p || a._val_p) return (toRational() == a.toRational()); 484 | return (_val_d == a._val_d); 485 | } 486 | 487 | inline bool operator!=(const PM_Rational& a) const 488 | { 489 | if (_val_p || a._val_p) return (toRational() != a.toRational()); 490 | return (_val_d != a._val_d); 491 | } 492 | 493 | inline PM_Rational& operator=(const PM_Rational& a) 494 | { 495 | if (_val_p || a._val_p) 496 | { 497 | if (this == (&a)) return *this; 498 | if (_val_p) delete _val_p; 499 | if (a._val_p) _val_p = new EXACT_NT(*a._val_p); 500 | else _val_p = NULL; 501 | } 502 | _val_d = a._val_d; 503 | return *this; 504 | } 505 | 506 | inline void setFromRational(const EXACT_NT& a) 507 | { 508 | if (_val_p) delete _val_p; 509 | _val_p = new EXACT_NT(a); 510 | _val_d = EXACT_NT_TO_DOUBLE(a); 511 | } 512 | 513 | inline void setFromDouble(double a) 514 | { 515 | if (_val_p) { delete _val_p; _val_p = NULL; } 516 | _val_d = a; 517 | } 518 | 519 | inline bool operator<(const PM_Rational& a) const 520 | { 521 | if (_val_p || a._val_p) return (toRational() < a.toRational()); 522 | return (_val_d < a._val_d); 523 | } 524 | 525 | inline bool operator>(const PM_Rational& a) const 526 | { 527 | if (_val_p || a._val_p) return (toRational() > a.toRational()); 528 | return (_val_d > a._val_d); 529 | } 530 | 531 | inline bool operator<=(const PM_Rational& a) const 532 | { 533 | if (_val_p || a._val_p) return (toRational() <= a.toRational()); 534 | return (_val_d <= a._val_d); 535 | } 536 | 537 | inline bool operator>=(const PM_Rational& a) const 538 | { 539 | if (_val_p || a._val_p) return (toRational() >= a.toRational()); 540 | return (_val_d >= a._val_d); 541 | } 542 | 543 | friend char orient2D(const PM_Rational& px, const PM_Rational& py, const PM_Rational& qx, const PM_Rational& qy, const PM_Rational& rx, const PM_Rational& ry); 544 | friend char orient3D(const class Point3c *t, const class Point3c *a, const class Point3c *b, const class Point3c *c); 545 | friend char inSphere3D(const class Point3c *pa, const class Point3c *pb, const class Point3c *pc, const class Point3c *pd, const class Point3c *pe); 546 | friend char inCircle3D(const class Point3c *pa, const class Point3c *pb, const class Point3c *pc, const class Point3c *pd); 547 | friend PM_Rational operator-(const PM_Rational& a); 548 | friend PM_Rational ceil(const PM_Rational& a); 549 | friend PM_Rational floor(const PM_Rational& a); 550 | friend PM_Rational round(const PM_Rational& a); 551 | 552 | friend class unprecise_number; 553 | 554 | inline void fput(FILE *fp) const { const EXACT_NT& n = toRational(); EXACT_NT_FPUT(&n, fp); } 555 | 556 | int fget(FILE *fp); 557 | }; 558 | 559 | inline PM_Rational operator-(const PM_Rational& a) 560 | { 561 | if (a.isOfRationalType()) return PM_Rational(-(*(a._val_p))); 562 | return PM_Rational(-a._val_d); 563 | } 564 | 565 | PM_Rational ceil(const PM_Rational& a); 566 | PM_Rational floor(const PM_Rational& a); 567 | PM_Rational round(const PM_Rational& a); 568 | inline PM_Rational fabs(const PM_Rational& a) { if (a < 0) return -a; else return a; } 569 | 570 | /**************** I/O operators ****************/ 571 | 572 | #define TMESH_TO_DOUBLE(x) ((x).toDouble()) 573 | #define TMESH_TO_FLOAT(x) ((x).toFloat()) 574 | #define TMESH_TO_INT(x) ((x).toInt()) 575 | #define TMESH_TO_NEAREST_DOUBLE(x) ((x).toNearestDouble()) 576 | #define TMESH_TO_LOWER_DOUBLE(x) ((x).toLowerDouble()) 577 | #define TMESH_TO_UPPER_DOUBLE(x) ((x).toUpperDouble()) 578 | #define TMESH_IS_NONZERO(x) ((x).sign()) 579 | #define TMESH_IS_ZERO(x) (!(x).sign()) 580 | 581 | #define TMESH_OMP_CLAUSES firstprivate(tmesh_thread_initializer) copyin(PM_Rational::use_rationals) 582 | 583 | #else 584 | 585 | typedef double PM_Rational; 586 | 587 | #define TMESH_TO_DOUBLE(x) (x) 588 | #define TMESH_TO_FLOAT(x) ((float)(x)) 589 | #define TMESH_TO_INT(x) ((int)(x)) 590 | #define TMESH_TO_NEAREST_DOUBLE(x) (x) 591 | #define TMESH_TO_LOWER_DOUBLE(x) (x) 592 | #define TMESH_TO_UPPER_DOUBLE(x) (x) 593 | #define TMESH_IS_NONZERO(x) ((x)!=0) 594 | #define TMESH_IS_ZERO(x) ((x)==0) 595 | 596 | #define TMESH_OMP_CLAUSES 597 | 598 | #endif 599 | 600 | typedef PM_Rational coord; 601 | 602 | #define TMESH_DETERMINANT3X3(a11, a12, a13, a21, a22, a23, a31, a32, a33) ((a11)*((a22)*(a33) - (a23)*(a32)) - (a12)*((a21)*(a33) - (a23)*(a31)) + (a13)*((a21)*(a32) - (a22)*(a31))) 603 | 604 | } //namespace T_MESH 605 | 606 | #endif //_COORDINATES_H 607 | 608 | -------------------------------------------------------------------------------- /include/expansion.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * expansion.h * 3 | * This file is part of the TMesh_Kernel Library * 4 | * * 5 | * Authors: Marco Attene * 6 | * Copyright(C) 2012: IMATI-GE / CNR * 7 | * IMATI-GE / CNR is Consiglio Nazionale delle Ricerche * 8 | * Istituto di Matematica Applicata e Tecnologie Informatiche * 9 | * Genova (Italy) * 10 | * * 11 | * TMesh_Kernel is free software; you can redistribute it and/or modify * 12 | * it under the terms of the GNU Lesser General Public License as published * 13 | * by the Free Software Foundation; either version 3 of the License, or (at * 14 | * your option) any later version. * 15 | * * 16 | * TMesh_Kernel is distributed in the hope that it will be useful, but * 17 | * WITHOUT ANY WARRANTY; without even the implied warranty of * 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser * 19 | * General Public License for more details. * 20 | * * 21 | * You should have received a copy of the GNU Lesser General Public License * 22 | * along with TMesh_Kernel. If not, see http://www.gnu.org/licenses/. * 23 | * * 24 | ****************************************************************************/ 25 | 26 | #ifndef EXPANSION_H 27 | #define EXPANSION_H 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #ifndef FABS 36 | #define FABS(a) fabs(a) 37 | #endif 38 | #define TO_NONNEGATIVE(d) ((d) = (FABS(d))) 39 | 40 | 41 | // The following macros are fast implementations of basic expansion arithmetic due 42 | // to Dekker, Knuth, Priest, Shewchuk, and others. 43 | 44 | // See Y. Hida, X. S. Li, D. H. Bailey "Algorithms for Quad-Double Precision Floating Point Arithmetic" 45 | 46 | // Sums 47 | #define Quick_Two_Sum(a, b, x, y) x = a + b; y = b - (x - a) 48 | #define Two_Sum(a, b, x, y) x = a + b; _bv = x - a; y = (a - (x - _bv)) + (b - _bv) 49 | #define Two_One_Sum(a1, a0, b, x2, x1, x0) Two_Sum(a0, b , _i, x0); Two_Sum(a1, _i, x2, x1) 50 | 51 | // Differences 52 | #define Two_Diff(a, b, x, y) x = a - b; _bv = a - x; y = (a - (x + _bv)) + (_bv - b) 53 | #define Two_One_Diff(a1, a0, b, x2, x1, x0) Two_Diff(a0, b , _i, x0); Two_Sum( a1, _i, x2, x1) 54 | 55 | // Products 56 | #define Split(a, _ah, _al) _c = 1.3421772800000003e+008 * a; _ah = _c - (_c - a); _al = a - _ah 57 | #define Two_Prod_PreSplit(a, b, _bh, _bl, x, y) x = a * b; Split(a, _ah, _al); y = (_al * _bl) - (((x - (_ah * _bh)) - (_al * _bh)) - (_ah * _bl)) 58 | #define Two_Product_2Presplit(a, _ah, _al, b, _bh, _bl, x, y) x = a * b; y = (_al * _bl) - (((x - _ah * _bh) - (_al * _bh)) - (_ah * _bl)) 59 | 60 | 61 | // An instance of the following must be created to access functions for expansion arithmetic 62 | class expansionObject 63 | { 64 | // Temporary vars used in low-level arithmetic 65 | double _bv, _c, _ah, _al, _bh, _bl, _i, _j, _k, _l, _0, _1, _2, _u3; 66 | 67 | public: 68 | expansionObject() {} 69 | 70 | inline void two_Sum(const double a, const double b, double* xy) { Two_Sum(a, b, xy[1], xy[0]); } 71 | 72 | inline void two_Diff(const double a, const double b, double* xy) { Two_Diff(a, b, xy[1], xy[0]); } 73 | 74 | // [x,y] = [a]*[b] Multiplies two expansions [a] and [b] of length one 75 | inline void Two_Prod(const double a, const double b, double& x, double& y) 76 | { 77 | x = a * b; 78 | Split(a, _ah, _al); Split(b, _bh, _bl); 79 | y = ((_ah * _bh - x) + _ah * _bl + _al * _bh) + _al * _bl; 80 | } 81 | inline void Two_Prod(const double a, const double b, double* xy) { Two_Prod(a, b, xy[1], xy[0]); } 82 | 83 | 84 | // [x,y] = [a]^2 Squares an expansion of length one 85 | inline void Square(const double a, double& x, double& y) 86 | { 87 | x = a * a; 88 | Split(a, _ah, _al); 89 | y = (_al * _al) - ((x - (_ah * _ah)) - ((_ah + _ah) * _al)); 90 | } 91 | inline void Square(const double a, double* xy) { Square(a, xy[1], xy[0]); } 92 | 93 | // [x2,x1,x0] = [a1,a0]-[b] Subtracts an expansion [b] of length one from an expansion [a1,a0] of length two 94 | inline void two_One_Diff(const double a1, const double a0, const double b, double& x2, double& x1, double& x0) 95 | { Two_One_Diff(a1, a0, b, x2, x1, x0); } 96 | inline void two_One_Diff(const double* a, const double b, double* x) { two_One_Diff(a[1], a[0], b, x[2], x[1], x[0]); } 97 | 98 | // [x3,x2,x1,x0] = [a1,a0]*[b] Multiplies an expansion [a1,a0] of length two by an expansion [b] of length one 99 | inline void Two_One_Prod(const double a1, const double a0, const double b, double& x3, double& x2, double& x1, double& x0) 100 | { 101 | Split(b, _bh, _bl); 102 | Two_Prod_PreSplit(a0, b, _bh, _bl, _i, x0); Two_Prod_PreSplit(a1, b, _bh, _bl, _j, _0); 103 | Two_Sum(_i, _0, _k, x1); Quick_Two_Sum(_j, _k, x3, x2); 104 | } 105 | inline void Two_One_Prod(const double* a, const double b, double* x) { Two_One_Prod(a[1], a[0], b, x[3], x[2], x[1], x[0]); } 106 | 107 | // [x3,x2,x1,x0] = [a1,a0]+[b1,b0] Calculates the sum of two expansions of length two 108 | inline void Two_Two_Sum(const double a1, const double a0, const double b1, const double b0, double& x3, double& x2, double& x1, double& x0) 109 | { 110 | Two_One_Sum(a1, a0, b0, _j, _0, x0); Two_One_Sum(_j, _0, b1, x3, x2, x1); 111 | } 112 | inline void Two_Two_Sum(const double* a, const double* b, double* xy) { Two_Two_Sum(a[1], a[0], b[1], b[0], xy[3], xy[2], xy[1], xy[0]); } 113 | 114 | // [x3,x2,x1,x0] = [a1,a0]-[b1,b0] Calculates the difference between two expansions of length two 115 | inline void Two_Two_Diff(const double a1, const double a0, const double b1, const double b0, double& x3, double& x2, double& x1, double& x0) 116 | { 117 | Two_One_Diff(a1, a0, b0, _j, _0, x0); Two_One_Diff(_j, _0, b1, _u3, x2, x1); x3 = _u3; 118 | } 119 | inline void Two_Two_Diff(const double* a, const double* b, double* x) { Two_Two_Diff(a[1], a[0], b[1], b[0], x[3], x[2], x[1], x[0]); } 120 | 121 | // Calculates the second component 'y' of the expansion [x,y] = [a]-[b] when 'x' is known 122 | inline void Two_Diff_Back(const double a, const double b, double& x, double& y) { _bv = a - x; y = (a - (x + _bv)) + (_bv - b); } 123 | inline void Two_Diff_Back(const double a, const double b, double* xy) { Two_Diff_Back(a, b, xy[1], xy[0]); } 124 | 125 | // [h] = [a1,a0]^2 Squares an expansion of length 2 126 | // 'h' must be allocated by the caller with 6 components. 127 | void Two_Square(const double& a1, const double& a0, double* x); 128 | 129 | // [h7,h6,...,h0] = [a1,a0]*[b1,b0] Calculates the product of two expansions of length two. 130 | // 'h' must be allocated by the caller with eight components. 131 | void Two_Two_Prod(const double a1, const double a0, const double b1, const double b0, double* h); 132 | inline void Two_Two_Prod(const double* a, const double* b, double* xy) { Two_Two_Prod(a[1], a[0], b[1], b[0], xy); } 133 | 134 | // [h7,h6,...,h0] = [a1,a0]*[b1,b0] Calculates the product of two expansions of length two. 135 | // 'h' must be allocated by the caller with eight components. 136 | //void Two_Two_Prod(const double a1, const double a0, const double b1, const double b0, double *h); 137 | //inline void Two_Two_Prod(const double *a, const double *b, double *xy) { Two_Two_Prod(a[1], a[0], b[1], b[0], xy); } 138 | 139 | // [e] = -[e] Inplace inversion 140 | static void Gen_Invert(const int elen, double* e) { for (int i = 0; i < elen; i++) e[i] = -e[i]; } 141 | 142 | // [h] = [e] + [f] Sums two expansions and returns number of components of result 143 | // 'h' must be allocated by the caller with at least elen+flen components. 144 | int Gen_Sum(const int elen, const double* e, const int flen, const double* f, double* h); 145 | 146 | // Same as above, but 'h' is allocated internally. The caller must still call 'free' to release the memory. 147 | inline int Gen_Sum_With_Alloc(const int elen, const double* e, const int flen, const double* f, double** h) 148 | { 149 | *h = (double*)malloc((elen + flen) * sizeof(double)); 150 | return Gen_Sum(elen, e, flen, f, *h); 151 | } 152 | 153 | // [h] = [e] + [f] Subtracts two expansions and returns number of components of result 154 | // 'h' must be allocated by the caller with at least elen+flen components. 155 | int Gen_Diff(const int elen, const double* e, const int flen, const double* f, double* h); 156 | 157 | // Same as above, but 'h' is allocated internally. The caller must still call 'free' to release the memory. 158 | inline int Gen_Diff_With_Alloc(const int elen, const double* e, const int flen, const double* f, double** h) 159 | { 160 | *h = (double*)malloc((elen + flen) * sizeof(double)); 161 | return Gen_Diff(elen, e, flen, f, *h); 162 | } 163 | 164 | // [h] = [e] * b Multiplies an expansion by a scalar 165 | // 'h' must be allocated by the caller with at least elen*2 components. 166 | int Gen_Scale(const int elen, const double* e, const double& b, double* h); 167 | 168 | // [h] = [e] * 2 Multiplies an expansion by 2 169 | // 'h' must be allocated by the caller with at least elen components. This is exact up to overflows. 170 | inline void Double(const int elen, const double* e, double* h) const { for (int i = 0; i < elen; i++) h[i] = 2 * e[i]; } 171 | 172 | // [h] = [a] * [b] 173 | // 'h' must be allocated by the caller with at least 2*alen*blen components. 174 | int Sub_product(const int alen, const double* a, const int blen, const double* b, double* h); 175 | 176 | // [h] = [a] * [b] 177 | // 'h' must be allocated by the caller with at least MAX(2*alen*blen, 8) components. 178 | int Gen_Product(const int alen, const double* a, const int blen, const double* b, double* h); 179 | 180 | // Same as above, but 'h' is allocated internally. The caller must still call 'free' to release the memory. 181 | inline int Gen_Product_With_Alloc(const int alen, const double* a, const int blen, const double* b, double** h) 182 | { 183 | int h_len = alen * blen * 2; 184 | if (h_len < 8) h_len = 8; 185 | *h = (double*)malloc(h_len * sizeof(double)); 186 | return Gen_Product(alen, a, blen, b, *h); 187 | } 188 | 189 | 190 | // Assume that *h is pre-allocated with hlen doubles. 191 | // If more elements are required, *h is re-allocated internally. 192 | // In any case, the function returns the size of the resulting expansion. 193 | // The caller must verify whether reallocation took place, and possibly call 'free' to release the memory. 194 | // When reallocation takes place, *h becomes different from its original value. 195 | 196 | inline int Double_With_PreAlloc(const int elen, const double* e, double** h, const int hlen) 197 | { 198 | int newlen = elen; 199 | if (hlen < newlen) *h = (double*)malloc(newlen * sizeof(double)); 200 | //if (hlen < newlen) printf("REALLOC %d bytes\n", newlen); 201 | Double(elen, e, *h); 202 | return newlen; 203 | } 204 | 205 | inline int Gen_Scale_With_PreAlloc(const int elen, const double* e, const double& b, double** h, const int hlen) 206 | { 207 | int newlen = elen * 2; 208 | if (hlen < newlen) *h = (double*)malloc(newlen * sizeof(double)); 209 | return Gen_Scale(elen, e, b, *h); 210 | } 211 | 212 | inline int Gen_Sum_With_PreAlloc(const int elen, const double* e, const int flen, const double* f, double** h, const int hlen) 213 | { 214 | int newlen = elen + flen; 215 | if (hlen < newlen) *h = (double*)malloc(newlen * sizeof(double)); 216 | return Gen_Sum(elen, e, flen, f, *h); 217 | } 218 | 219 | inline int Gen_Diff_With_PreAlloc(const int elen, const double* e, const int flen, const double* f, double** h, const int hlen) 220 | { 221 | int newlen = elen + flen; 222 | if (hlen < newlen) *h = (double*)malloc(newlen * sizeof(double)); 223 | return Gen_Diff(elen, e, flen, f, *h); 224 | } 225 | 226 | inline int Gen_Product_With_PreAlloc(const int alen, const double* a, const int blen, const double* b, double** h, const int hlen) 227 | { 228 | int newlen = alen * blen * 2; 229 | if (hlen < newlen || hlen < 8) 230 | { 231 | if (newlen < 8) newlen = 8; 232 | *h = (double*)malloc(newlen * sizeof(double)); 233 | } 234 | return Gen_Product(alen, a, blen, b, *h); 235 | } 236 | 237 | // Approximates the expansion to a double 238 | static double To_Double(const int elen, const double* e); 239 | }; 240 | 241 | #endif // EXPANSION_H 242 | -------------------------------------------------------------------------------- /include/mixedPredicates.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * mixedPredicates.h * 3 | * This file is part of the TMesh_Kernel Library * 4 | * * 5 | * Authors: Marco Attene * 6 | * Copyright(C) 2012: IMATI-GE / CNR * 7 | * IMATI-GE / CNR is Consiglio Nazionale delle Ricerche * 8 | * Istituto di Matematica Applicata e Tecnologie Informatiche * 9 | * Genova (Italy) * 10 | * * 11 | * TMesh_Kernel is free software; you can redistribute it and/or modify * 12 | * it under the terms of the GNU Lesser General Public License as published * 13 | * by the Free Software Foundation; either version 3 of the License, or (at * 14 | * your option) any later version. * 15 | * * 16 | * TMesh_Kernel is distributed in the hope that it will be useful, but * 17 | * WITHOUT ANY WARRANTY; without even the implied warranty of * 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser * 19 | * General Public License for more details. * 20 | * * 21 | * You should have received a copy of the GNU Lesser General Public License * 22 | * along with TMesh_Kernel. If not, see http://www.gnu.org/licenses/. * 23 | * * 24 | ****************************************************************************/ 25 | 26 | #ifndef MIXED_PREDICATES 27 | #define MIXED_PREDICATES 28 | 29 | #include "unprecise_numbers.h" 30 | 31 | namespace T_MESH 32 | { 33 | class unprecise_number : public interval_number 34 | { 35 | public: 36 | inline unprecise_number(double a) : interval_number(a) {} 37 | inline unprecise_number(double a, double b) : interval_number(a, b) {} 38 | 39 | inline unprecise_number(const interval_number& b) : interval_number(b) {} 40 | 41 | #ifdef USE_HYBRID_KERNEL 42 | #ifdef USE_LAZY_KERNEL 43 | inline unprecise_number(const PM_Rational& a) 44 | { 45 | if (a.isOfRationalType()) init(a.getVal().unprecise()); 46 | else init(a.getDVal()); 47 | } 48 | #else 49 | inline unprecise_number(const PM_Rational& a) 50 | { 51 | if (a.isOfRationalType()) init(a.getVal()); 52 | else init(a.getDVal()); 53 | } 54 | #endif 55 | #endif 56 | 57 | }; 58 | 59 | // Orient 2D 60 | template 61 | inline T unpreciseOrient2d_T(T& ax, T& ay, T& bx, T& by, T& cx, T& cy) 62 | { 63 | return (((ax - cx)*(by - cy)) - ((ay - cy)*(bx - cx))); 64 | } 65 | 66 | #ifdef USE_HYBRID_KERNEL 67 | template 68 | inline T unpreciseOrient2d(const PM_Rational& px, const PM_Rational& py, const PM_Rational& qx, const PM_Rational& qy, const PM_Rational& rx, const PM_Rational& ry) 69 | { 70 | T ax(px), ay(py), bx(qx), by(qy), cx(rx), cy(ry); 71 | return unpreciseOrient2d_T(ax, ay, bx, by, cx, cy); 72 | } 73 | 74 | #endif 75 | 76 | template 77 | inline T unpreciseOrient2d(const double& px, const double& py, const double& qx, const double& qy, const double& rx, const double& ry) 78 | { 79 | T ax(px), ay(py), bx(qx), by(qy), cx(rx), cy(ry); 80 | return unpreciseOrient2d_T(ax, ay, bx, by, cx, cy); 81 | } 82 | 83 | // Orient 3D 84 | template 85 | inline T unpreciseOrient3d_T(T& a11, T& a12, T& a13, T& a21, T& a22, T& a23, T& a31, T& a32, T& a33, T& cx, T& cy, T& cz) 86 | { 87 | a11 -= cx; a12 -= cy; a13 -= cz; 88 | a21 -= cx; a22 -= cy; a23 -= cz; 89 | a31 -= cx; a32 -= cy; a33 -= cz; 90 | return ((a11)*((a22)*(a33)-(a23)*(a32)) - (a12)*((a21)*(a33)-(a23)*(a31)) + (a13)*((a21)*(a32)-(a22)*(a31))); 91 | } 92 | 93 | template 94 | inline T unpreciseOrient3d(const Point3c *d, const Point3c *a, const Point3c *b, const Point3c *c) 95 | { 96 | T a11(d->x), a12(d->y), a13(d->z); 97 | T a21(a->x), a22(a->y), a23(a->z); 98 | T a31(b->x), a32(b->y), a33(b->z); 99 | T cx(c->x), cy(c->y), cz(c->z); 100 | return unpreciseOrient3d_T(a11, a12, a13, a21, a22, a23, a31, a32, a33, cx, cy, cz); 101 | } 102 | 103 | template 104 | inline T unpreciseOrient3d(const double *d, const double *a, const double *b, const double *c) 105 | { 106 | T a11((d)[0]), a12((d)[1]), a13((d)[2]); 107 | T a21((a)[0]), a22((a)[1]), a23((a)[2]); 108 | T a31((b)[0]), a32((b)[1]), a33((b)[2]); 109 | T cx((c)[0]), cy((c)[1]), cz((c)[2]); 110 | return unpreciseOrient3d_T(a11, a12, a13, a21, a22, a23, a31, a32, a33, cx, cy, cz); 111 | } 112 | 113 | // Insphere 114 | template 115 | inline T unpreciseInsphere_T(T& pex, T& pey, T& pez, T& aex, T& aey, T& aez, T& bex, T& bey, T& bez, T& cex, T& cey, T& cez, T& dex, T& dey, T& dez) 116 | { 117 | aex -= pex; aey -= pey; aez -= pez; 118 | bex -= pex; bey -= pey; bez -= pez; 119 | cex -= pex; cey -= pey; cez -= pez; 120 | dex -= pex; dey -= pey; dez -= pez; 121 | 122 | T ab(aex * bey); ab -= (bex * aey); 123 | T bc(bex * cey); bc -= (cex * bey); 124 | T cd(cex * dey); cd -= (dex * cey); 125 | T da(dex * aey); da -= (aex * dey); 126 | T ac(aex * cey); ac -= (cex * aey); 127 | T bd(bex * dey); bd -= (dex * bey); 128 | 129 | T abc(aez * bc - bez * ac + cez * ab); 130 | T bcd(bez * cd - cez * bd + dez * bc); 131 | T cda(cez * da + dez * ac + aez * cd); 132 | T dab(dez * ab + aez * bd + bez * da); 133 | 134 | T alift(aex * aex + aey * aey + aez * aez); 135 | T blift(bex * bex + bey * bey + bez * bez); 136 | T clift(cex * cex + cey * cey + cez * cez); 137 | T dlift(dex * dex + dey * dey + dez * dez); 138 | 139 | return ((dlift * abc - clift * dab) + (blift * cda - alift * bcd)); 140 | } 141 | 142 | template 143 | inline T unpreciseInsphere(const Point3c *pa, const Point3c *pb, const Point3c *pc, const Point3c *pd, const Point3c *pe) 144 | { 145 | T pex(pe->x), pey(pe->y), pez(pe->z); 146 | T aex(pa->x), aey(pa->y), aez(pa->z); 147 | T bex(pb->x), bey(pb->y), bez(pb->z); 148 | T cex(pc->x), cey(pc->y), cez(pc->z); 149 | T dex(pd->x), dey(pd->y), dez(pd->z); 150 | return unpreciseInsphere_T(pex, pey, pez, aex, aey, aez, bex, bey, bez, cex, cey, cez, dex, dey, dez); 151 | } 152 | 153 | template 154 | inline T unpreciseInsphere(const double *pa, const double *pb, const double *pc, const double *pd, const double *pe) 155 | { 156 | T pex((pe)[0]), pey(pe[1]), pez(pe[2]); 157 | T aex((pa)[0]), aey(pa[1]), aez(pa[2]); 158 | T bex((pb)[0]), bey(pb[1]), bez(pb[2]); 159 | T cex((pc)[0]), cey(pc[1]), cez(pc[2]); 160 | T dex((pd)[0]), dey((pd)[1]), dez((pd)[2]); 161 | return unpreciseInsphere_T(pex, pey, pez, aex, aey, aez, bex, bey, bez, cex, cey, cez, dex, dey, dez); 162 | } 163 | 164 | 165 | // InCircle3D 166 | template 167 | inline T unpreciseInCircle3D_T(T& aex, T& aey, T& aez, T& bex, T& bey, T& bez, T& cex, T& cey, T& cez, T& dex, T& dey, T& dez) 168 | { 169 | T p10x = bex - aex, p10y = bey - aey, p10z = bez - aez; 170 | T l1 = p10x * p10x + p10y * p10y + p10z * p10z; 171 | T p20x = cex - aex, p20y = cey - aey, p20z = cez - aez; 172 | T l2 = p20x * p20x + p20y * p20y + p20z * p20z; 173 | T p30x = dex - aex, p30y = dey - aey, p30z = dez - aez; 174 | T l3 = p30x * p30x + p30y * p30y + p30z * p30z; 175 | 176 | T a11 = l1 * T(2); 177 | T a12 = (p10x * p20x + p10y * p20y + p10z * p20z) * T(2); 178 | T a22 = l2 * T(2); 179 | T a31 = (p30x * p10x + p30y * p10y + p30z * p10z) * T(2); 180 | T a32 = (p30x * p20x + p30y * p20y + p30z * p20z) * T(2); 181 | 182 | T det = (a11 * a22) - (a12 * a12); 183 | T r = ((((a31 * ((a22 * l1) - (a12 * l2)))) + (a32 * ((a11 * l2) - (a12 * l1)))) - (det * l3)); 184 | 185 | return det*r; 186 | } 187 | 188 | template 189 | inline T unpreciseInCircle3D(const Point3c *pa, const Point3c *pb, const Point3c *pc, const Point3c *pd) 190 | { 191 | T aex(pa->x), aey(pa->y), aez(pa->z); 192 | T bex(pb->x), bey(pb->y), bez(pb->z); 193 | T cex(pc->x), cey(pc->y), cez(pc->z); 194 | T dex(pd->x), dey(pd->y), dez(pd->z); 195 | return unpreciseInCircle3D_T(aex, aey, aez, bex, bey, bez, cex, cey, cez, dex, dey, dez); 196 | } 197 | 198 | template 199 | inline T unpreciseInCircle3D(const double *pa, const double *pb, const double *pc, const double *pd) 200 | { 201 | T aex((pa)[0]), aey(pa[1]), aez(pa[2]); 202 | T bex((pb)[0]), bey(pb[1]), bez(pb[2]); 203 | T cex((pc)[0]), cey(pc[1]), cez(pc[2]); 204 | T dex((pd)[0]), dey((pd)[1]), dez((pd)[2]); 205 | return unpreciseInCircle3D_T(aex, aey, aez, bex, bey, bez, cex, cey, cez, dex, dey, dez); 206 | } 207 | 208 | #ifdef USE_LAZY_KERNEL 209 | inline tmesh_fraction preciseOrient2d(const PM_Rational& px, const PM_Rational& py, const PM_Rational& qx, const PM_Rational& qy, const PM_Rational& rx, const PM_Rational& ry) 210 | { 211 | tmesh_fraction qpx(px.toRational().exact()), qpy(py.toRational().exact()); 212 | tmesh_fraction qqx(qx.toRational().exact()), qqy(qy.toRational().exact()); 213 | tmesh_fraction qrx(rx.toRational().exact()), qry(ry.toRational().exact()); 214 | return unpreciseOrient2d_T(qpx, qpy, qqx, qqy, qrx, qry); 215 | } 216 | 217 | inline tmesh_fraction preciseOrient3d(const Point3c *d, const Point3c *a, const Point3c *b, const Point3c *c) 218 | { 219 | tmesh_fraction a11(d->x.toRational().exact()), a12(d->y.toRational().exact()), a13(d->z.toRational().exact()); 220 | tmesh_fraction a21(a->x.toRational().exact()), a22(a->y.toRational().exact()), a23(a->z.toRational().exact()); 221 | tmesh_fraction a31(b->x.toRational().exact()), a32(b->y.toRational().exact()), a33(b->z.toRational().exact()); 222 | tmesh_fraction cx(c->x.toRational().exact()), cy(c->y.toRational().exact()), cz(c->z.toRational().exact()); 223 | return unpreciseOrient3d_T(a11, a12, a13, a21, a22, a23, a31, a32, a33, cx, cy, cz); 224 | } 225 | 226 | inline tmesh_fraction preciseInsphere(const Point3c *pa, const Point3c *pb, const Point3c *pc, const Point3c *pd, const Point3c *pe) 227 | { 228 | tmesh_fraction pex(pe->x.toRational().exact()), pey(pe->y.toRational().exact()), pez(pe->z.toRational().exact()); 229 | tmesh_fraction aex(pa->x.toRational().exact()), aey(pa->y.toRational().exact()), aez(pa->z.toRational().exact()); 230 | tmesh_fraction bex(pb->x.toRational().exact()), bey(pb->y.toRational().exact()), bez(pb->z.toRational().exact()); 231 | tmesh_fraction cex(pc->x.toRational().exact()), cey(pc->y.toRational().exact()), cez(pc->z.toRational().exact()); 232 | tmesh_fraction dex(pd->x.toRational().exact()), dey(pd->y.toRational().exact()), dez(pd->z.toRational().exact()); 233 | return unpreciseInsphere_T(pex, pey, pez, aex, aey, aez, bex, bey, bez, cex, cey, cez, dex, dey, dez); 234 | } 235 | 236 | inline tmesh_fraction preciseInCircle3D(const Point3c *pa, const Point3c *pb, const Point3c *pc, const Point3c *pd) 237 | { 238 | tmesh_fraction aex(pa->x.toRational().exact()), aey(pa->y.toRational().exact()), aez(pa->z.toRational().exact()); 239 | tmesh_fraction bex(pb->x.toRational().exact()), bey(pb->y.toRational().exact()), bez(pb->z.toRational().exact()); 240 | tmesh_fraction cex(pc->x.toRational().exact()), cey(pc->y.toRational().exact()), cez(pc->z.toRational().exact()); 241 | tmesh_fraction dex(pd->x.toRational().exact()), dey(pd->y.toRational().exact()), dez(pd->z.toRational().exact()); 242 | return unpreciseInCircle3D_T(aex, aey, aez, bex, bey, bez, cex, cey, cez, dex, dey, dez); 243 | } 244 | #endif 245 | } 246 | 247 | #endif // MIXED_PREDICATES 248 | -------------------------------------------------------------------------------- /include/point.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * point.h * 3 | * This file is part of the TMesh_Kernel Library * 4 | * * 5 | * Authors: Marco Attene * 6 | * Copyright(C) 2012: IMATI-GE / CNR * 7 | * IMATI-GE / CNR is Consiglio Nazionale delle Ricerche * 8 | * Istituto di Matematica Applicata e Tecnologie Informatiche * 9 | * Genova (Italy) * 10 | * * 11 | * TMesh_Kernel is free software; you can redistribute it and/or modify * 12 | * it under the terms of the GNU Lesser General Public License as published * 13 | * by the Free Software Foundation; either version 3 of the License, or (at * 14 | * your option) any later version. * 15 | * * 16 | * TMesh_Kernel is distributed in the hope that it will be useful, but * 17 | * WITHOUT ANY WARRANTY; without even the implied warranty of * 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser * 19 | * General Public License for more details. * 20 | * * 21 | * You should have received a copy of the GNU Lesser General Public License * 22 | * along with TMesh_Kernel. If not, see http://www.gnu.org/licenses/. * 23 | * * 24 | ****************************************************************************/ 25 | 26 | #ifndef _POINT_H 27 | #define _POINT_H 28 | 29 | #include "basics.h" 30 | 31 | namespace T_MESH 32 | { 33 | //! Orientation predicates on PM_Rationals 34 | 35 | class Point3c; 36 | char orient2D(const PM_Rational& px, const PM_Rational& py, const PM_Rational& qx, const PM_Rational& qy, const PM_Rational& rx, const PM_Rational& ry); 37 | char orient3D(const Point3c *t, const Point3c *a, const Point3c *b, const Point3c *c); 38 | char inSphere3D(const Point3c *pa, const Point3c *pb, const Point3c *pc, const Point3c *pd, const Point3c *pe); 39 | char inCircle3D(const Point3c *pa, const Point3c *pb, const Point3c *pc, const Point3c *pd); 40 | 41 | 42 | //! Geometric point definition 43 | 44 | //! This class represents a point in the Euclidean 3D space. It can be used 45 | //! to represent 3D vectors originating at (0,0,0) and terminating at the 46 | //! corresponding point. Several methods of this class are intended to 47 | //! manipulate vectors rather than points; for example, a call of the 48 | //! method normalize is an actual normalization if the object is a vector, 49 | //! but it has to be intended as a projection on the unit sphere if the 50 | //! object is intended to be a point. An object of type Point3c is a triplet 51 | //! of coordinates. Each coordinate is a number of type 'coord' which can be 52 | //! often treated as a standard double. Operations on points include addition, 53 | //! subtraction, cross and dot product, and others. This class implements 54 | //! several useful operations using vector arithmethic. For example, 55 | //! the simple piece of code "A = B*C;" assignes to A the value of the dot 56 | //! product of B and C. 57 | 58 | class Point3c 59 | { 60 | public : 61 | coord x,y,z; //!< Coordinates 62 | 63 | //! Creates a new point with coordinates (0,0,0). 64 | inline Point3c() : x(0), y(0), z(0) { } 65 | 66 | //! Creates a new point with the same coordinates as 's'. 67 | inline Point3c(const Point3c *s) : x(s->x), y(s->y), z(s->z) { } 68 | 69 | //! Creates a new point with the same coordinates as 's'. 70 | inline Point3c(const Point3c& s) : x(s.x), y(s.y), z(s.z) { } 71 | 72 | //! Creates a new point with coordinates (a,b,c). 73 | inline Point3c(const coord& a, const coord& b, const coord& c) : x(a), y(b), z(c) { } 74 | 75 | //! Do not remove this. It makes the compiler produce a vtable for this object. 76 | TMESH_VIRTUAL bool isPoint() const { return true; } 77 | 78 | //! Set the coordinates to (a,b,c). 79 | inline void setValue(const coord& a, const coord& b, const coord& c) { x = a; y = b; z = c; } 80 | 81 | //! Set the coordinates as those of 'p' 82 | inline void setValue(const Point3c& p) { x = p.x; y = p.y; z = p.z; } 83 | 84 | //! Set the coordinates as those of '*p' 85 | inline void setValue(const Point3c *p) { x = p->x; y = p->y; z = p->z; } 86 | 87 | //! Returns the vector difference 88 | inline Point3c operator-(const Point3c& p) const { return Point3c(x - p.x, y - p.y, z - p.z); } 89 | 90 | //! Returns the vector sum 91 | inline Point3c operator+(const Point3c& p) const { return Point3c(x + p.x, y + p.y, z + p.z); } 92 | 93 | //! Sums another point 94 | inline void operator+=(const Point3c& p) { x += p.x; y += p.y; z += p.z; } 95 | 96 | //! Subtracts another point 97 | inline void operator-=(const Point3c& p) { x -= p.x; y -= p.y; z -= p.z; } 98 | 99 | //! Returns the Cross Product 100 | inline Point3c operator&(const Point3c& p) const { return Point3c(y*p.z - z*p.y, z*p.x - x*p.z, x*p.y - y*p.x); } 101 | 102 | //! Returns the Dot Product 103 | inline coord operator*(const Point3c& p) const { return (x*p.x + y*p.y + z*p.z); } 104 | 105 | //! Returns the product with a scalar 106 | inline Point3c operator*(const coord& d) const { return Point3c(x*d, y*d, z*d); } 107 | 108 | //! Multiplies by a scalar 109 | inline void operator*=(const coord& m) { x *= m; y *= m; z *= m; } 110 | 111 | //! Divides by a scalar 112 | inline void operator/=(const coord& m) { x /= m; y /= m; z /= m; } 113 | 114 | //! Returns the vector divided by the scalar 115 | inline Point3c operator/(const coord& d) const { return Point3c(x / d, y / d, z / d); } 116 | 117 | //! TRUE iff coordinates are equal 118 | inline bool operator==(const Point3c& p) const { return (x == p.x && y == p.y && z == p.z); } 119 | 120 | //! FALSE iff coordinates are equal 121 | inline bool operator!=(const Point3c& p) const { return (x != p.x || y != p.y || z != p.z); } 122 | 123 | //! TRUE iff this is lexycographically smaller than s 124 | bool operator<(const Point3c& s) const; 125 | 126 | //! Get the i'th coordinate 127 | inline coord& at(unsigned char i) { return (i == 0) ? (x) : ((i == 1) ? (y) : (z)); } 128 | inline const coord& at(unsigned char i) const { return (i == 0) ? (x) : ((i == 1) ? (y) : (z)); } 129 | inline coord& operator[](unsigned char i) { return (i == 0) ? (x) : ((i == 1) ? (y) : (z)); } 130 | inline const coord& operator[](unsigned char i) const { return (i == 0) ? (x) : ((i == 1) ? (y) : (z)); } 131 | 132 | //! Returns the inverse vector 133 | inline Point3c inverse() const { return Point3c(-x, -y, -z); } 134 | 135 | //! Inverts the vector 136 | inline void invert() { x = -x; y = -y; z = -z; } 137 | 138 | //! TRUE if vector is (0,0,0) 139 | inline bool isNull() const { return (TMESH_IS_ZERO(x) && TMESH_IS_ZERO(y) && TMESH_IS_ZERO(z)); } 140 | 141 | //! Returns the solution of the linear system Ax = d, where A is a 3x3 matrix whose rows are row1, row2 and row3, d = this 142 | Point3c linearSystem(const Point3c& row1, const Point3c& row2, const Point3c& row3) const; 143 | 144 | //! Projects the vector on the plane with normal 'n' passing through the origin. 145 | inline void project(const Point3c *n) { setValue((*this) - ((*n)*((*this)*(*n)))); } 146 | 147 | //! Returns the projection of the point on the straight line though 'a' and 'b'. 148 | Point3c projection(const Point3c *a, const Point3c *b) const; 149 | 150 | //! Returns the projection of the point on the plane though 'a', 'b' and 'c'. 151 | Point3c projection(const Point3c *a, const Point3c *b, const Point3c *c) const; 152 | 153 | //! Exact orientation test. 154 | //! Return value is positive iff the tetrahedron (this,a,b,c) has a positive volume; 155 | //! It is negative iff the tetrahedron (this,a,b,c) has a negative volume; 156 | //! It is zero iff the tetrahedron (this,a,b,c) has a zero volume. 157 | inline char exactOrientation(const Point3c *a, const Point3c *b, const Point3c *c) const { return orient3D(this, a, b, c); } 158 | inline char exactOrientation(const Point3c& a, const Point3c& b, const Point3c& c) const { return orient3D(this, &a, &b, &c); } 159 | 160 | //! Return value is positive iff this point belongs to the interior of the sphere 161 | //! by a,b,c,d. Negative if outside. Zero if on the sphere's surface. 162 | //! Assumes that a->exactOrientation(b, c, d) is positive. Otherwise the sign is flipped. 163 | inline char inSphere(const Point3c *a, const Point3c *b, const Point3c *c, const Point3c *d) const { return inSphere3D(a, b, c, d, this); } 164 | inline char inSphere(const Point3c& a, const Point3c& b, const Point3c& c, const Point3c& d) const { return inSphere3D(&a, &b, &c, &d, this); } 165 | 166 | //! Return value is positive iff this point belongs to the interior of the circle 167 | //! by a,b,c. Negative if outside. Zero if on the circle. 168 | //! Assumes that this and a,b,c are coplanar. Result is undetermined otherwise. 169 | inline char incircle3D(const Point3c *a, const Point3c *b, const Point3c *c) const { return inCircle3D(a, b, c, this); } 170 | inline char incircle3D(const Point3c& a, const Point3c& b, const Point3c& c) const { return inCircle3D(&a, &b, &c, this); } 171 | 172 | //! Exact misalignment test. Returns TRUE iff points are not aligned. 173 | bool exactMisalignment(const Point3c *a, const Point3c *b) const; 174 | inline bool notAligned(const Point3c *a, const Point3c *b) const { return exactMisalignment(a, b); } 175 | 176 | //! Exact planar side test. Returns TRUE iff 'this', Q, A and B are coplanar 177 | //! and 'this' and Q are (properly) on the same side of A-B. 178 | //! Coplanarity is not checked, result is undetermined if 179 | //! 'this', Q, A and B are not coplanar. 180 | bool exactSameSideOnPlane(const Point3c *Q, const Point3c *A, const Point3c *B) const; 181 | 182 | //! true if 'p' is a point of the segment v1-v2 (endpoints excluded) 183 | static bool pointInInnerSegment(const Point3c *p, const Point3c *v1, const Point3c *v2); 184 | 185 | //! true if 'p' is a point of the segment v1-v2 (endpoints included) 186 | static bool pointInSegment(const Point3c *p, const Point3c *v1, const Point3c *v2); 187 | 188 | //! true if the coplanar point 'p' is in the inner area of v1-v2-v3. 189 | //! Undetermined if points are not coplanar. 190 | static bool pointInInnerTriangle(const Point3c *p, const Point3c *v1, const Point3c *v2, const Point3c *v3); 191 | 192 | //! true if the coplanar point 'p' is either in the inner area of v1-v2-v3 or on its border. 193 | //! Undetermined if points are not coplanar. 194 | static bool pointInTriangle(const Point3c *p, const Point3c *v1, const Point3c *v2, const Point3c *v3); 195 | 196 | //! true if the interior of (p1-p2) properly intersects the interior of (sp1-sp2). 197 | //! Collinear overlapping segments are not considered to be properly intersecting. 198 | static bool innerSegmentsCross(const Point3c& p1, const Point3c& p2, const Point3c& sp1, const Point3c& sp2); 199 | 200 | //! true if (p1-p2) properly intersects (sp1-sp2) at any point (endpoints included). 201 | //! Collinear overlapping segments are not considered to be properly intersecting. 202 | static bool segmentsIntersect(const Point3c *p1, const Point3c *p2, const Point3c *sp1, const Point3c *sp2); 203 | 204 | //! true if inner segment (s1-s2) intersects the triangle v1-v2-v3 (border excluded) at a single point 205 | static bool segmentProperlyIntersectsTriangle(const Point3c *s1, const Point3c *s2, const Point3c *v1, const Point3c *v2, const Point3c *v3); 206 | 207 | //! true if segment (s1-s2) intersects the triangle v1-v2-v3 (border included). 208 | static bool segmentIntersectsTriangle(const Point3c *s1, const Point3c *s2, const Point3c *v1, const Point3c *v2, const Point3c *v3); 209 | 210 | //! true if segment (s1-s2) intersects the triangle v1-v2-v3 (border included). 211 | //! Accelerated version - relative orientations are passed as parameters. 212 | static bool segmentIntersectsTriangle(const Point3c *s1, const Point3c *s2, const Point3c *v1, const Point3c *v2, const Point3c *v3, char o1, char o2); 213 | 214 | //! Itersection point between lines p-q and r-s. Return INFINITE_POINT if lines are either non-intersecting or degenerate. 215 | static Point3c lineLineIntersection(const Point3c& p, const Point3c& q, const Point3c& r, const Point3c& s); 216 | static Point3c tmpExact_lineLineIntersection(const Point3c& p, const Point3c& q, const Point3c& r, const Point3c& s); 217 | 218 | //! Itersection point between line p-q and plane r-s-t. Return INFINITE_POINT for parallel/degenerate args. 219 | static Point3c linePlaneIntersection(const Point3c& p, const Point3c& q, const Point3c& r, const Point3c& s, const Point3c& t); 220 | static Point3c tmpExact_linePlaneIntersection(const Point3c& p, const Point3c& q, const Point3c& r, const Point3c& s, const Point3c& t); 221 | 222 | //! Itersection point between line p-q and plane for 'v0' with directional vector 'd'. Return INFINITE_POINT for parallel/degenerate args. 223 | static Point3c linePlaneIntersection(const Point3c& p, const Point3c& q, const Point3c& v0, const Point3c& d); 224 | static Point3c tmpExact_linePlaneIntersection(const Point3c& p, const Point3c& q, const Point3c& v0, const Point3c& d); 225 | 226 | //! Itersection of three planes. Return INFINITE_POINT for parallel/degenerate args. 227 | static Point3c threePlanesIntersection(const Point3c& v1, const Point3c& v2, const Point3c& v3, 228 | const Point3c& w1, const Point3c& w2, const Point3c& w3, 229 | const Point3c& u1, const Point3c& u2, const Point3c& u3); 230 | 231 | static Point3c tmpExact_threePlanesIntersection(const Point3c& v1, const Point3c& v2, const Point3c& v3, 232 | const Point3c& w1, const Point3c& w2, const Point3c& w3, 233 | const Point3c& u1, const Point3c& u2, const Point3c& u3); 234 | 235 | //! Squared distance from origin 236 | inline coord squaredLength() const { return (x*x + y*y + z*z); } 237 | 238 | //! Squared distance from '*b' 239 | inline coord squaredDistance(const Point3c *b) const { return (((*(this)) - (*b)).squaredLength()); } 240 | 241 | //! Squared area of the triangle p-q-r. 242 | inline static coord squaredTriangleArea3D(const Point3c& p, const Point3c& q, const Point3c& r) { return ((p - r)&(q - r)).squaredLength()*0.25; } 243 | 244 | //! Squared distance from straight line through 'a' and 'b' 245 | coord squaredDistanceFromLine(const Point3c *a, const Point3c *b) const; 246 | 247 | //! Squared distance from plane through 'app_point' and 'having directional vector 'dirver' 248 | coord squaredDistanceFromPlane(const Point3c& dirver, const Point3c& app_point) const; 249 | 250 | //! Line-line closest point computation. 251 | //! Computes the closest points of the line passing through this and this2, 252 | //! and the line passing through p1 and p2. The computed points are used to 253 | //! initialize the coordinates of cpOnThis and cpOnOther. The method 254 | //! returns FALSE if the lines are parallel or degenerate, TRUE otherwise. 255 | bool closestPoints(const Point3c *this2, const Point3c *p1, const Point3c *p2, Point3c *cpOnThis, Point3c *cpOnOther) const; 256 | 257 | 258 | // FUNCTIONS BELOW THIS LINE MAY RETURN APPROXIMATE/NOT ROBUST RESULTS EVEN WHEN USING RATIONALS 259 | 260 | 261 | 262 | //! Distance from origin 263 | inline double length() const { return sqrt(TMESH_TO_DOUBLE(squaredLength())); } 264 | 265 | //! Divides the vector by its length. If isNull() the application exits with an error. 266 | Point3c& normalize(); 267 | 268 | //! Rotates the vector around 'axis' by 'ang' radians ccw. 269 | void rotate(const Point3c& axis, const double& ang); 270 | 271 | //! Distance from 'b' 272 | inline double distance(const Point3c& b) const { return (((*(this)) - (b)).length()); } 273 | 274 | //! Distance from '*b' 275 | inline double distance(const Point3c *b) const { return (((*(this)) - (*b)).length()); } 276 | 277 | //! Distance from straight line through 'a' and 'b' 278 | double distanceFromLine(const Point3c *a, const Point3c *b) const; 279 | 280 | //! Distance from straight line through 'a' and 'b'. *cc is set to the closest line point. 281 | double distanceFromLine(const Point3c *a, const Point3c *b, Point3c *cc) const; 282 | 283 | double distanceFromEdge(const Point3c *a, const Point3c *b) const; //!< Distance from segment a-b 284 | 285 | //! Distance from segment a-b. *cc is set to the closest edge point. 286 | double distanceFromEdge(const Point3c *a, const Point3c *b, Point3c *cc) const; 287 | 288 | //! Distance between the straight lines through (this) - l1_p2 and l2_p1 - l2_p2. 289 | double distanceLineLine(const Point3c *l1_p2, const Point3c *l2_p1, const Point3c *l2_p2) const; 290 | 291 | //! Angle between this vector and 'v' in radians. 292 | double getAngle(const Point3c& v) const; 293 | 294 | //! Angle defined by in radians. 295 | inline double getAngle(const Point3c& a, const Point3c& b) const { return (a - (*this)).getAngle(b - (*this)); } 296 | 297 | //! Angle defined by <*a, *this, *b> in radians. 298 | inline double getAngle(const Point3c *a, const Point3c *b) const { return ((*a) - (*this)).getAngle((*b) - (*this)); } 299 | 300 | //! These functions round the coordinates to the closest floating point representation 301 | void snapToSinglePrecisionFloat() { x = float(TMESH_TO_NEAREST_DOUBLE(x)); y = float(TMESH_TO_NEAREST_DOUBLE(y)); z = float(TMESH_TO_NEAREST_DOUBLE(z)); } 302 | void snapToDoublePrecisionFloat() { x = TMESH_TO_NEAREST_DOUBLE(x); y = TMESH_TO_NEAREST_DOUBLE(y); z = TMESH_TO_NEAREST_DOUBLE(z); } 303 | 304 | //! Prints the coordinates of the point to a file handler. stdout is the default. 305 | void printPoint(FILE *fp = stdout) const { fprintf(fp, "%f %f %f,\n", TMESH_TO_FLOAT(x), TMESH_TO_FLOAT(y), TMESH_TO_FLOAT(z)); } // Debug 306 | }; 307 | 308 | //! Lexycographic comparison to be used with jqsort() or abstractHeap. 309 | int xyzCompare(const void *p1, const void *p2); 310 | 311 | //! Static point with 'infinite' coordinates. 312 | extern const Point3c INFINITE_POINT; 313 | 314 | // The following is wrong! -INF returns TRUE. Should be fixed... 315 | //! Checks whether a point is INFINITE_POINT. 316 | #define IS_FINITE_POINT(p) ((p).x < TMESH_INFINITY && (p).y < TMESH_INFINITY && (p).z < TMESH_INFINITY) 317 | 318 | 319 | //! This is mainly for backward compatibility with older ImatiSTL-based Apps. 320 | //! This class adds a generic 'info' field to store additional information. 321 | 322 | class Point : public Point3c 323 | { 324 | public: 325 | void *info; //!< Further information 326 | 327 | //! Creates a new point with coordinates (0,0,0). 328 | inline Point() : Point3c() { } 329 | 330 | //! Creates a new point with the same coordinates as 's'. The info field is not copied. 331 | inline Point(const Point3c *s) : Point3c(s), info(NULL) { } 332 | 333 | //! Creates a new point with the same coordinates as 's'. The info field is not copied. 334 | inline Point(const Point3c& s) : Point3c(s), info(NULL) { } 335 | 336 | //! Creates a new point with the same coordinates as 's'. The info field is not copied. 337 | inline Point(const Point *s) : Point3c(s), info(NULL) { } 338 | 339 | //! Creates a new point with the same coordinates as 's'. The info field is not copied. 340 | inline Point(const Point& s) : Point3c(s), info(NULL) { } 341 | 342 | //! Creates a new point with coordinates (a,b,c). 343 | inline Point(const coord& a, const coord& b, const coord& c) : Point3c(a, b, c), info(NULL) { } 344 | }; 345 | 346 | } //namespace T_MESH 347 | 348 | #endif // _POINT_H 349 | 350 | -------------------------------------------------------------------------------- /include/tmesh_kernel.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * tmesh_kernel.h * 3 | * This file is part of the TMesh_Kernel Library * 4 | * * 5 | * Authors: Marco Attene * 6 | * Copyright(C) 2012: IMATI-GE / CNR * 7 | * IMATI-GE / CNR is Consiglio Nazionale delle Ricerche * 8 | * Istituto di Matematica Applicata e Tecnologie Informatiche * 9 | * Genova (Italy) * 10 | * * 11 | * TMesh_Kernel is free software; you can redistribute it and/or modify * 12 | * it under the terms of the GNU Lesser General Public License as published * 13 | * by the Free Software Foundation; either version 3 of the License, or (at * 14 | * your option) any later version. * 15 | * * 16 | * TMesh_Kernel is distributed in the hope that it will be useful, but * 17 | * WITHOUT ANY WARRANTY; without even the implied warranty of * 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser * 19 | * General Public License for more details. * 20 | * * 21 | * You should have received a copy of the GNU Lesser General Public License * 22 | * along with TMesh_Kernel. If not, see http://www.gnu.org/licenses/. * 23 | * * 24 | ****************************************************************************/ 25 | 26 | #ifndef _TMESH_KERNEL_H 27 | #define _TMESH_KERNEL_H 28 | 29 | #include "basics.h" 30 | #include "point.h" 31 | 32 | #endif //_TMESH_KERNEL_H 33 | -------------------------------------------------------------------------------- /include/unprecise_numbers.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * unprecise_numbers.h * 3 | * This file is part of the TMesh_Kernel Library * 4 | * * 5 | * Authors: Marco Attene * 6 | * Copyright(C) 2012: IMATI-GE / CNR * 7 | * IMATI-GE / CNR is Consiglio Nazionale delle Ricerche * 8 | * Istituto di Matematica Applicata e Tecnologie Informatiche * 9 | * Genova (Italy) * 10 | * * 11 | * TMesh_Kernel is free software; you can redistribute it and/or modify * 12 | * it under the terms of the GNU Lesser General Public License as published * 13 | * by the Free Software Foundation; either version 3 of the License, or (at * 14 | * your option) any later version. * 15 | * * 16 | * TMesh_Kernel is distributed in the hope that it will be useful, but * 17 | * WITHOUT ANY WARRANTY; without even the implied warranty of * 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser * 19 | * General Public License for more details. * 20 | * * 21 | * You should have received a copy of the GNU Lesser General Public License * 22 | * along with TMesh_Kernel. If not, see http://www.gnu.org/licenses/. * 23 | * * 24 | ****************************************************************************/ 25 | 26 | #ifndef UNPRECISE_NUMBERS 27 | #define UNPRECISE_NUMBERS 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include "coordinates.h" 36 | 37 | namespace T_MESH 38 | { 39 | // Interval_number 40 | class interval_number 41 | { 42 | public: 43 | double low, high; 44 | 45 | inline interval_number() {} 46 | inline interval_number(double a) : low(a), high(a) {} 47 | inline interval_number(double a, double b) : low(a), high(b) {} 48 | inline interval_number(const interval_number& b) : low(b.low), high(b.high) {} 49 | 50 | #ifdef USE_HYBRID_KERNEL 51 | inline interval_number(const tmesh_fraction& a) { init(a); } 52 | 53 | inline void init(const tmesh_fraction& a) 54 | { 55 | casted_double eps; 56 | low = high = eps.d = a.get_d(); 57 | eps.u &= EXPONENT_MASK; 58 | if (eps.u == EXPONENT_MASK) return; // Not a finite number (NaN or INFINITY) 59 | int s = sgn(a); 60 | if (eps.u>MACH_DIFFEPS) 61 | { 62 | eps.u -= MACH_DIFFEPS; 63 | if (s>0) high += eps.d; 64 | if (s<0) low -= eps.d; 65 | } else 66 | { 67 | if (s<0) low = -DBL_MIN; 68 | if (s>0) high = DBL_MIN; 69 | } 70 | } 71 | #endif 72 | inline void init(const interval_number& b) { low = b.low; high = b.high; } 73 | inline void init(const double b) { low = high = b; } 74 | 75 | inline bool disjointWith(const interval_number& b) const { return (high < b.low || low > b.high); } 76 | 77 | inline bool isExact() const { return (low == high); } 78 | inline bool signIsReliable() const { return (low>0 || high <0 || (low==0 && high==0)); } 79 | inline char sign() const { return (low > 0) ? (1) : ((low < 0) ? (-1) : (0)); } 80 | 81 | inline double getMid() const { return (low + high)*0.5; } 82 | 83 | inline bool operator<(const interval_number& b) const { return (high(const interval_number& b) const { return (low>b.high); } 85 | inline bool operator<=(const interval_number& b) const { return (high <= b.low); } 86 | inline bool operator>=(const interval_number& b) const { return (low >= b.high); } 87 | 88 | inline interval_number& operator=(const interval_number& b) { low = b.low; high = b.high; return *this; } 89 | 90 | inline interval_number& operator+=(const interval_number& b) { low = -((-low) - b.low); high += b.high; return *this; } 91 | inline interval_number& operator-=(const interval_number& b) { low = -(b.high - low); high -= b.low; return *this; } 92 | inline interval_number& operator*=(const interval_number& b) { return operator=((*this) * b); } // This should be optimized 93 | inline interval_number& operator/=(const interval_number& b) { return operator=((*this) / b); } // This should be optimized 94 | 95 | inline interval_number operator+(const interval_number& b) const { return interval_number(-((-low)-b.low), high+b.high); } 96 | 97 | inline interval_number operator-(const interval_number& b) const { return interval_number(-(b.high - low), high - b.low); } 98 | 99 | inline interval_number operator*(const interval_number& b) const 100 | { 101 | casted_double l1(low), h1(high), l2(b.low), h2(b.high); 102 | uint64_t conf = (l1.is_negative() << 3) + (h1.is_negative() << 2) + (l2.is_negative() << 1) + (h2.is_negative()); 103 | switch (conf) 104 | { 105 | case 0: return interval_number(-((-low)*b.low), high*b.high); 106 | case 2: return interval_number(-((-high)*b.low), high*b.high); 107 | case 3: return interval_number(-((-high)*b.low), low*b.high); 108 | case 8: return interval_number(-((-low)*b.high), high*b.high); 109 | case 10: 110 | double ll, lh, hl, hh; 111 | ll = low*b.low; lh = -((-low)*b.high); hl = -((-high)*b.low); hh = high*b.high; 112 | if (hl < lh) lh = hl; 113 | if (ll > hh) hh = ll; 114 | return interval_number(lh, hh); 115 | case 11: return interval_number(-((-high)*b.low), low*b.low); 116 | case 12: return interval_number(-((-low)*b.high), high*b.low); 117 | case 14: return interval_number(-((-low)*b.high), low*b.low); 118 | case 15: return interval_number(-((-high)*b.high), low*b.low); 119 | }; 120 | //TMesh::error("interval_number: inconsistent interval."); 121 | return interval_number(TMESH_NAN); 122 | } 123 | 124 | inline interval_number operator/(const interval_number& b) const 125 | { 126 | casted_double l1(low), h1(high), l2(b.low), h2(b.high); 127 | uint64_t conf = (l1.is_negative() << 3) + (h1.is_negative() << 2) + (l2.is_negative() << 1) + (h2.is_negative()); 128 | switch (conf) 129 | { 130 | case 0: return interval_number(-((-low)/b.high), high/b.low); 131 | case 2: return interval_number(TMESH_NAN); 132 | case 3: return interval_number(-((-high) / b.high), low / b.low); 133 | case 8: return interval_number(-((-low) / b.low), high / b.low); 134 | case 10: return interval_number(TMESH_NAN); 135 | case 11: return interval_number(-((-high) / b.high), low / b.high); 136 | case 12: return interval_number(-((-low) / b.low), high / b.high); 137 | case 14: return interval_number(-TMESH_NAN); 138 | case 15: return interval_number(-((-high) / b.low), low / b.high); 139 | }; 140 | //TMesh::error("interval_number: inconsistent interval."); 141 | return interval_number(TMESH_NAN); 142 | } 143 | }; 144 | 145 | 146 | 147 | 148 | //////////////////////////////////////////////// LAZY NUMBERS ////////////////////////////////////////////// 149 | 150 | #ifdef USE_LAZY_KERNEL 151 | 152 | typedef enum 153 | { 154 | none, 155 | sum, difference, product, division 156 | } operation_id; 157 | 158 | 159 | // Two possibilities to parallelize the exact computation of a lazy number: 160 | // 1) Safe and lower memory footprint 161 | // > the subdags are released immediately upon exact calculation 162 | // 2) Higher memory footprint but much faster concurrency (seems to be safe too) 163 | // > the subdags are lazily released upon destruction of the last number that used them 164 | 165 | //#define TMESH_SAFE_LOW_MEM_FOOTPRINT 166 | 167 | 168 | // This is the number's DAG 169 | 170 | 171 | class lazy_num_base 172 | { 173 | protected: 174 | interval_number approximate_value; 175 | tmesh_fraction *exact_value; // NULL, unless previously computed 176 | operation_id operation; // If 'none', this is a leaf 177 | 178 | public: 179 | inline lazy_num_base() : exact_value(NULL) {} 180 | 181 | inline lazy_num_base(const operation_id o) : exact_value(NULL), operation(o) {} 182 | 183 | inline lazy_num_base(double d) : 184 | approximate_value(d), 185 | exact_value(NULL), 186 | operation(operation_id::none) 187 | { 188 | } 189 | 190 | inline lazy_num_base(const tmesh_fraction& a) : 191 | approximate_value(a), 192 | exact_value(new tmesh_fraction(a)), 193 | operation(operation_id::none) 194 | { 195 | } 196 | 197 | inline ~lazy_num_base() 198 | { 199 | if (exact_value) delete exact_value; 200 | } 201 | 202 | inline const interval_number& unprecise() const { return approximate_value; } 203 | 204 | void print() const; 205 | 206 | inline const tmesh_fraction& exact() 207 | { 208 | #ifdef TMESH_SAFE_LOW_MEM_FOOTPRINT 209 | #pragma omp critical 210 | #endif 211 | if (!exact_value) compute_exact(); 212 | return *exact_value; 213 | } 214 | 215 | private: 216 | void compute_exact(); 217 | }; 218 | 219 | class lazy_num_binary : public lazy_num_base 220 | { 221 | public: 222 | std::shared_ptr operand_1, operand_2; 223 | 224 | inline lazy_num_binary(const std::shared_ptr& a, const std::shared_ptr& b, const operation_id op) : lazy_num_base(op), 225 | operand_1(a), 226 | operand_2(b) 227 | { 228 | switch (op) 229 | { 230 | case operation_id::sum: 231 | approximate_value = operand_1->unprecise() + operand_2->unprecise(); 232 | return; 233 | case operation_id::difference: 234 | approximate_value = operand_1->unprecise() - operand_2->unprecise(); 235 | return; 236 | case operation_id::product: 237 | approximate_value = operand_1->unprecise() * operand_2->unprecise(); 238 | return; 239 | case operation_id::division: 240 | approximate_value = operand_1->unprecise() / operand_2->unprecise(); 241 | return; 242 | default: 243 | return; 244 | } 245 | } 246 | }; 247 | 248 | 249 | class lazy_num 250 | { 251 | std::shared_ptr root; 252 | 253 | public: 254 | inline lazy_num(double d) { root = std::make_shared(d); } 255 | inline lazy_num(const tmesh_fraction& a) { root = std::make_shared(a); } 256 | inline lazy_num(const lazy_num& n) : root(n.root) { } 257 | inline lazy_num(const lazy_num& o1, const lazy_num& o2, const operation_id& op) { root = std::make_shared(o1.root, o2.root, op); } 258 | 259 | inline lazy_num& operator=(const lazy_num& n) { root = n.root; return *this; } 260 | 261 | inline const interval_number& unprecise() const { return root->unprecise(); } 262 | inline const double approx() const { return root->unprecise().getMid(); } 263 | inline const tmesh_fraction& exact() const { return root->exact(); } 264 | inline bool isPrecise() const { return (root->unprecise().isExact()); } 265 | 266 | inline lazy_num operator+(const lazy_num& n) const { return lazy_num(*this, n, operation_id::sum); } 267 | inline lazy_num operator-(const lazy_num& n) const { return lazy_num(*this, n, operation_id::difference); } 268 | inline lazy_num operator*(const lazy_num& n) const { return lazy_num(*this, n, operation_id::product); } 269 | inline lazy_num operator/(const lazy_num& n) const { return lazy_num(*this, n, operation_id::division); } 270 | 271 | inline lazy_num& operator+=(const lazy_num& n) { root = std::make_shared(root, n.root, operation_id::sum); return *this; } 272 | inline lazy_num& operator-=(const lazy_num& n) { root = std::make_shared(root, n.root, operation_id::difference); return *this; } 273 | inline lazy_num& operator*=(const lazy_num& n) { root = std::make_shared(root, n.root, operation_id::product); return *this; } 274 | inline lazy_num& operator/=(const lazy_num& n) { root = std::make_shared(root, n.root, operation_id::division); return *this; } 275 | 276 | void print() const { root->print(); } 277 | 278 | void fput(FILE *fp) const { gmp_fprintf(fp, "%Qd", exact().get_mpq_t()); } 279 | 280 | int fget(FILE *fp) 281 | { 282 | root = std::make_shared(0.0); 283 | return gmp_fscanf(fp, "%Qd", root->exact().get_mpq_t()); 284 | } 285 | 286 | inline int sign() const 287 | { 288 | if (unprecise().signIsReliable()) return unprecise().sign(); 289 | else return sgn(exact()); 290 | } 291 | 292 | inline bool operator==(const lazy_num& n) const 293 | { 294 | if (unprecise().disjointWith(n.unprecise())) return false; 295 | if (isPrecise() && n.isPrecise()) return (unprecise().low == n.unprecise().low); 296 | return (exact() == n.exact()); 297 | } 298 | 299 | inline bool operator!=(const lazy_num& n) const 300 | { 301 | if (unprecise().disjointWith(n.unprecise())) return true; 302 | if (isPrecise() && n.isPrecise()) return (unprecise().low != n.unprecise().low); 303 | return (exact() != n.exact()); 304 | } 305 | 306 | inline bool operator<(const lazy_num& n) const 307 | { 308 | if (unprecise() < n.unprecise()) return true; 309 | if (unprecise() >= n.unprecise()) return false; 310 | return (exact() n.unprecise()) return false; 317 | return (exact() <= n.exact()); 318 | } 319 | 320 | inline bool operator>(const lazy_num& n) const 321 | { 322 | if (unprecise() > n.unprecise()) return true; 323 | if (unprecise() <= n.unprecise()) return false; 324 | return (exact()>n.exact()); 325 | } 326 | 327 | inline bool operator>=(const lazy_num& n) const 328 | { 329 | if (unprecise() >= n.unprecise()) return true; 330 | if (unprecise() < n.unprecise()) return false; 331 | return (exact() >= n.exact()); 332 | } 333 | }; 334 | 335 | 336 | 337 | #endif // USE_LAZY_KERNEL 338 | 339 | } 340 | 341 | #endif // UNPRECISE_NUMBERS 342 | -------------------------------------------------------------------------------- /lgpl.txt: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /mpir/README.txt: -------------------------------------------------------------------------------- 1 | This directory must be enriched with two additional files besides this README. 2 | 3 | ***** On Windows MSVC ***** 4 | 5 | The two additional files are: 6 | 1) mpir.h 7 | 2) One of: mpir64.lib (on MS Windows 64bit), mpir32.lib (on MS Windows 32bit) 8 | 9 | To create these two files: 10 | 11 | Option (1): check if your MSVC version matches one of the subfolders in this diorectory. If so, just copy from there. Otherwise use option 2 below. 12 | 13 | Option (2): 14 | 15 | 1) Clone or download MPIR from https://github.com/BrianGladman/mpir 16 | 2) cd mpir-master/msvc/vsXX (XX is one of 13, 15, 17, 19, ...select the one matching your MSVC version) 17 | 3) open mpir.sln 18 | 4) select Debug/Release and Win32/x64 based on your needs 19 | 5) build the project lib_mpir_gc 20 | 6) You will find both mpir.h and mpir.lib in msvc/vsXX/lib_mpir_gc/x64/Release/ (if you compiled for x64 in Release mode). 21 | 7) Copy these two files in the directory containing this README file. 22 | 8) Rename mpir.lib to mpir64.lib (if you compiled for x64, otherwise rename to mpir32.lib). 23 | 24 | 25 | ***** On Mac OSX ***** 26 | 27 | The two additional files are: 28 | 1) mpir.h 29 | 2) libmpir.a 30 | 31 | To create these two files: 32 | 1) brew install mpir 33 | 2) The two files will be placed in /usr/local/lib/libmpir.a and /usr/local/include/mpir.h 34 | 3) Copy both of them in the directory containing this README file. 35 | 36 | 37 | ***** On Linux ***** 38 | 39 | The two additional files are: 40 | 1) mpir.h 41 | 2) libmpir.a 42 | 43 | To create these two files: 44 | 1) sudo apt-get install yasm m4 build-essential unzip wget -y 45 | 2) wget http://mpir.org/mpir-3.0.0 46 | 3) unzip mpir-3.0.0.zip 47 | 4) cd mpir-3.0.0 48 | 5) ./configure 49 | 6) make 50 | 7) The two files will be placed in .libs/libmpir.a and ./mpir.h 51 | 8) Copy these two files in the directory containing this README file. 52 | -------------------------------------------------------------------------------- /mpir/vs2013/mpir32.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MarcoAttene/TMesh_Kernel/8eb249c999c3178fdc5d4fb5b48831032a6bd9a7/mpir/vs2013/mpir32.lib -------------------------------------------------------------------------------- /mpir/vs2013/mpir64.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MarcoAttene/TMesh_Kernel/8eb249c999c3178fdc5d4fb5b48831032a6bd9a7/mpir/vs2013/mpir64.lib -------------------------------------------------------------------------------- /src/coordinates.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * coordinates.cpp * 3 | * This file is part of the TMesh_Kernel Library * 4 | * * 5 | * Authors: Marco Attene * 6 | * Copyright(C) 2012: IMATI-GE / CNR * 7 | * IMATI-GE / CNR is Consiglio Nazionale delle Ricerche * 8 | * Istituto di Matematica Applicata e Tecnologie Informatiche * 9 | * Genova (Italy) * 10 | * * 11 | * TMesh_Kernel is free software; you can redistribute it and/or modify * 12 | * it under the terms of the GNU Lesser General Public License as published * 13 | * by the Free Software Foundation; either version 3 of the License, or (at * 14 | * your option) any later version. * 15 | * * 16 | * TMesh_Kernel is distributed in the hope that it will be useful, but * 17 | * WITHOUT ANY WARRANTY; without even the implied warranty of * 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser * 19 | * General Public License for more details. * 20 | * * 21 | * You should have received a copy of the GNU Lesser General Public License * 22 | * along with TMesh_Kernel. If not, see http://www.gnu.org/licenses/. * 23 | * * 24 | ****************************************************************************/ 25 | 26 | #include "coordinates.h" 27 | #include 28 | #include 29 | 30 | namespace T_MESH 31 | { 32 | #ifdef USE_HYBRID_KERNEL 33 | 34 | // Default behaviour = FILTERED KERNEL 35 | #ifdef WIN32 36 | char PM_Rational::use_rationals = 0; 37 | #else 38 | thread_local char PM_Rational::use_rationals = 0; 39 | #endif 40 | 41 | double to_upper_double(const tmesh_fraction& a) 42 | { 43 | if (sgn(a) <= 0) return a.get_d(); // Default truncation is equivalent to round-up 44 | 45 | casted_double eps; 46 | double ret = eps.d = a.get_d(); 47 | eps.u &= EXPONENT_MASK; 48 | if (eps.u == EXPONENT_MASK) return ret; // Not a finite number 49 | if (eps.u>MACH_DIFFEPS) 50 | { 51 | eps.u -= MACH_DIFFEPS; 52 | return (ret + eps.d); 53 | } else return DBL_MIN; 54 | } 55 | 56 | double to_lower_double(const tmesh_fraction& a) 57 | { 58 | if (sgn(a) >= 0) return a.get_d(); // Default truncation is equivalent to round-down 59 | 60 | casted_double eps; 61 | double ret = eps.d = a.get_d(); 62 | eps.u &= EXPONENT_MASK; 63 | if (eps.u == EXPONENT_MASK) return ret; // Not a finite number 64 | if (eps.u>MACH_DIFFEPS) 65 | { 66 | eps.u -= MACH_DIFFEPS; 67 | return (ret - eps.d); 68 | } else return -DBL_MIN; 69 | } 70 | 71 | int PM_Rational::fget(FILE *fp) 72 | { 73 | tmesh_fraction a; 74 | if (gmp_fscanf(fp, "%Qd", a.get_mpq_t())) 75 | { 76 | double d = a.get_d(); 77 | if (a == tmesh_fraction(d)) setFromDouble(d); 78 | else setFromRational(EXACT_NT(a)); 79 | return 1; 80 | } 81 | return 0; 82 | } 83 | 84 | PM_Rational ceil(const PM_Rational& a) 85 | { 86 | if (a.isOfRationalType()) 87 | { 88 | mpz_t n, d, f; 89 | const EXACT_NT& en = a.toRational(); 90 | mpz_init(n); mpz_init(d); mpz_init(f); 91 | mpz_set(n, EXACT_NT_NUMERATOR(&en)); 92 | mpz_set(d, EXACT_NT_DENOMINATOR(&en)); 93 | mpz_cdiv_q(f, n, d); 94 | mpz_clear(n); mpz_clear(d); 95 | return PM_Rational(tmesh_fraction(f)); 96 | } 97 | else 98 | return PM_Rational(::ceil(a.getDVal())); 99 | } 100 | 101 | PM_Rational floor(const PM_Rational& a) 102 | { 103 | if (a.isOfRationalType()) 104 | { 105 | mpz_t n, d, f; 106 | const EXACT_NT& en = a.toRational(); 107 | mpz_init(n); mpz_init(d); mpz_init(f); 108 | mpz_set(n, EXACT_NT_NUMERATOR(&en)); 109 | mpz_set(d, EXACT_NT_DENOMINATOR(&en)); 110 | mpz_fdiv_q(f, n, d); 111 | mpz_clear(n); mpz_clear(d); 112 | return PM_Rational(tmesh_fraction(f)); 113 | } else 114 | return PM_Rational(::floor(a.getDVal())); 115 | } 116 | 117 | PM_Rational round(const PM_Rational& a) 118 | { 119 | if (a.isOfRationalType()) 120 | { 121 | mpz_t n, d, f, c; 122 | mpz_init(n); mpz_init(d); mpz_init(f); mpz_init(c); 123 | const EXACT_NT& en = a.toRational(); 124 | mpz_set(n, EXACT_NT_NUMERATOR(&en)); 125 | mpz_set(d, EXACT_NT_DENOMINATOR(&en)); 126 | mpz_cdiv_q(c, n, d); 127 | mpz_clear(n); mpz_clear(d); 128 | PM_Rational fr = PM_Rational(tmesh_fraction(f)); 129 | PM_Rational cr = PM_Rational(tmesh_fraction(c)); 130 | mpz_clear(f); mpz_clear(c); 131 | return ((a - fr) < (cr - a)) ? (fr) : (cr); 132 | } else 133 | return PM_Rational(::round(a.getDVal())); 134 | } 135 | 136 | #ifdef USE_LAZY_KERNEL 137 | 138 | void lazy_num_base::compute_exact() 139 | { 140 | tmesh_fraction *nv; 141 | 142 | if (approximate_value.isExact()) 143 | { 144 | nv = new tmesh_fraction(approximate_value.low); 145 | } 146 | else 147 | { 148 | switch (operation) 149 | { 150 | case operation_id::none: 151 | nv = new tmesh_fraction(approximate_value.low); 152 | break; 153 | case operation_id::sum: 154 | nv = new tmesh_fraction(((lazy_num_binary *)this)->operand_1->exact() + ((lazy_num_binary *)this)->operand_2->exact()); 155 | break; 156 | case operation_id::difference: 157 | nv = new tmesh_fraction(((lazy_num_binary *)this)->operand_1->exact() - ((lazy_num_binary *)this)->operand_2->exact()); 158 | break; 159 | case operation_id::product: 160 | nv = new tmesh_fraction(((lazy_num_binary *)this)->operand_1->exact() * ((lazy_num_binary *)this)->operand_2->exact()); 161 | break; 162 | case operation_id::division: 163 | nv = new tmesh_fraction(((lazy_num_binary *)this)->operand_1->exact() / ((lazy_num_binary *)this)->operand_2->exact()); 164 | } 165 | } 166 | #ifndef TMESH_SAFE_LOW_MEM_FOOTPRINT 167 | #pragma omp critical 168 | #endif 169 | { 170 | if (exact_value == NULL) 171 | { 172 | exact_value = nv; 173 | #ifdef TMESH_SAFE_LOW_MEM_FOOTPRINT 174 | if (operation == operation_id::sum || operation == operation_id::difference || operation == operation_id::product || operation == operation_id::division) 175 | { 176 | if (((lazy_num_binary *)this)->operand_1.use_count()) ((lazy_num_binary *)this)->operand_1.reset(); 177 | if (((lazy_num_binary *)this)->operand_2.use_count()) ((lazy_num_binary *)this)->operand_2.reset(); 178 | } 179 | #endif 180 | operation = operation_id::none; 181 | if (!approximate_value.isExact()) approximate_value = interval_number(*exact_value); 182 | } else delete nv; 183 | } 184 | } 185 | 186 | void lazy_num_base::print() const 187 | { 188 | switch (operation) 189 | { 190 | case operation_id::none: 191 | printf("[ %f , %f]", approximate_value.low, approximate_value.high); 192 | return; 193 | case operation_id::sum: 194 | printf("( "); ((lazy_num_binary *)this)->operand_1->print(); printf(" + "); ((lazy_num_binary *)this)->operand_2->print(); printf(" )"); 195 | return; 196 | case operation_id::difference: 197 | printf("( "); ((lazy_num_binary *)this)->operand_1->print(); printf(" - "); ((lazy_num_binary *)this)->operand_2->print(); printf(" )"); 198 | return; 199 | case operation_id::product: 200 | printf("( "); ((lazy_num_binary *)this)->operand_1->print(); printf(" * "); ((lazy_num_binary *)this)->operand_2->print(); printf(" )"); 201 | return; 202 | case operation_id::division: 203 | printf("( "); ((lazy_num_binary *)this)->operand_1->print(); printf(" / "); ((lazy_num_binary *)this)->operand_2->print(); printf(" )"); 204 | } 205 | } 206 | 207 | #endif // USE_LAZY_KERNEL 208 | 209 | #endif // USE_HYBRID_KERNEL 210 | 211 | } //namespace T_MESH 212 | -------------------------------------------------------------------------------- /src/expansion.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * expansion.cpp * 3 | * This file is part of the TMesh_Kernel Library * 4 | * * 5 | * Authors: Marco Attene * 6 | * Copyright(C) 2012: IMATI-GE / CNR * 7 | * IMATI-GE / CNR is Consiglio Nazionale delle Ricerche * 8 | * Istituto di Matematica Applicata e Tecnologie Informatiche * 9 | * Genova (Italy) * 10 | * * 11 | * TMesh_Kernel is free software; you can redistribute it and/or modify * 12 | * it under the terms of the GNU Lesser General Public License as published * 13 | * by the Free Software Foundation; either version 3 of the License, or (at * 14 | * your option) any later version. * 15 | * * 16 | * TMesh_Kernel is distributed in the hope that it will be useful, but * 17 | * WITHOUT ANY WARRANTY; without even the implied warranty of * 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser * 19 | * General Public License for more details. * 20 | * * 21 | * You should have received a copy of the GNU Lesser General Public License * 22 | * along with TMesh_Kernel. If not, see http://www.gnu.org/licenses/. * 23 | * * 24 | ****************************************************************************/ 25 | 26 | /*****************************************************************************/ 27 | /* */ 28 | /* Arithmetic Expansion */ 29 | /* Code in this file is freely inspired from ideas first presented */ 30 | /* in Jonathan Richard Shewchuk's paper "Adaptive Precision Floating- */ 31 | /* Point Arithmetic and Fast Robust Geometric Predicates." Discrete & */ 32 | /* Computational Geometry (1998). */ 33 | /* */ 34 | /*****************************************************************************/ 35 | 36 | #include "expansion.h" 37 | #include "float.h" 38 | 39 | #pragma optimize("", off) 40 | 41 | void expansionObject::Two_Two_Prod(const double a1, const double a0, const double b1, const double b0, double* h) 42 | { 43 | double _ch, _cl, _m, _n; 44 | Split(a0, _ah, _al); 45 | Split(b0, _bh, _bl); 46 | Two_Product_2Presplit(a0, _ah, _al, b0, _bh, _bl, _i, h[0]); 47 | Split(a1, _ch, _cl); 48 | Two_Product_2Presplit(a1, _ch, _cl, b0, _bh, _bl, _j, _0); 49 | Two_Sum(_i, _0, _k, _1); 50 | Quick_Two_Sum(_j, _k, _l, _2); 51 | Split(b1, _bh, _bl); 52 | Two_Product_2Presplit(a0, _ah, _al, b1, _bh, _bl, _i, _0); 53 | Two_Sum(_1, _0, _k, h[1]); 54 | Two_Sum(_2, _k, _j, _1); 55 | Two_Sum(_l, _j, _m, _2); 56 | Two_Product_2Presplit(a1, _ch, _cl, b1, _bh, _bl, _j, _0); 57 | Two_Sum(_i, _0, _n, _0); 58 | Two_Sum(_1, _0, _i, h[2]); 59 | Two_Sum(_2, _i, _k, _1); 60 | Two_Sum(_m, _k, _l, _2); 61 | Two_Sum(_j, _n, _k, _0); 62 | Two_Sum(_1, _0, _j, h[3]); 63 | Two_Sum(_2, _j, _i, _1); 64 | Two_Sum(_l, _i, _m, _2); 65 | Two_Sum(_1, _k, _i, h[4]); 66 | Two_Sum(_2, _i, _k, h[5]); 67 | Two_Sum(_m, _k, h[7], h[6]); 68 | } 69 | 70 | int expansionObject::Gen_Sum(const int elen, const double *e, const int flen, const double *f, double *h) 71 | { 72 | double Q, Qn, hh, en = e[0], fn = f[0]; 73 | int e_k, f_k, h_k; 74 | 75 | h_k = e_k = f_k = 0; 76 | if ((fn > en) == (fn > -en)) { Q = en; e_k++; } else { Q = fn; f_k++; } 77 | 78 | if ((e_k < elen) && (f_k < flen)) 79 | { 80 | en = e[e_k]; fn = f[f_k]; 81 | if ((fn > en) == (fn > -en)) { Quick_Two_Sum(en, Q, Qn, hh); e_k++; } else { Quick_Two_Sum(fn, Q, Qn, hh); f_k++; } 82 | Q = Qn; 83 | if (hh != 0.0) h[h_k++] = hh; 84 | while ((e_k < elen) && (f_k < flen)) 85 | { 86 | en = e[e_k]; fn = f[f_k]; 87 | if ((fn > en) == (fn > -en)) { Two_Sum(Q, en, Qn, hh); e_k++; } else { Two_Sum(Q, fn, Qn, hh); f_k++; } 88 | Q = Qn; 89 | if (hh != 0.0) h[h_k++] = hh; 90 | } 91 | } 92 | 93 | while (e_k < elen) 94 | { 95 | en = e[e_k++]; 96 | Two_Sum(Q, en, Qn, hh); 97 | Q = Qn; 98 | if (hh != 0.0) h[h_k++] = hh; 99 | } 100 | 101 | while (f_k < flen) 102 | { 103 | fn = f[f_k++]; 104 | Two_Sum(Q, fn, Qn, hh); 105 | Q = Qn; 106 | if (hh != 0.0) h[h_k++] = hh; 107 | } 108 | if ((Q != 0.0) || (h_k == 0)) h[h_k++] = Q; 109 | 110 | return h_k; 111 | } 112 | 113 | int expansionObject::Gen_Diff(const int elen, const double *e, const int flen, const double *f, double *h) 114 | { 115 | double Q, Qn, hh, en = e[0], fn = -f[0]; 116 | int e_k, f_k, h_k; 117 | 118 | h_k = e_k = f_k = 0; 119 | if ((fn > en) == (fn > -en)) { Q = en; e_k++; } else { Q = fn; f_k++; } 120 | 121 | if ((e_k < elen) && (f_k < flen)) 122 | { 123 | en = e[e_k]; fn = -f[f_k]; 124 | if ((fn > en) == (fn > -en)) { Quick_Two_Sum(en, Q, Qn, hh); e_k++; } else { Quick_Two_Sum(fn, Q, Qn, hh); f_k++; } 125 | Q = Qn; 126 | if (hh != 0.0) h[h_k++] = hh; 127 | while ((e_k < elen) && (f_k < flen)) 128 | { 129 | en = e[e_k]; fn = -f[f_k]; 130 | if ((fn > en) == (fn > -en)) { Two_Sum(Q, en, Qn, hh); e_k++; } else { Two_Sum(Q, fn, Qn, hh); f_k++; } 131 | Q = Qn; 132 | if (hh != 0.0) h[h_k++] = hh; 133 | } 134 | } 135 | 136 | while (e_k < elen) 137 | { 138 | en = e[e_k++]; 139 | Two_Sum(Q, en, Qn, hh); 140 | Q = Qn; 141 | if (hh != 0.0) h[h_k++] = hh; 142 | } 143 | 144 | while (f_k < flen) 145 | { 146 | fn = -f[f_k++]; 147 | Two_Sum(Q, fn, Qn, hh); 148 | Q = Qn; 149 | if (hh != 0.0) h[h_k++] = hh; 150 | } 151 | if ((Q != 0.0) || (h_k == 0)) h[h_k++] = Q; 152 | 153 | return h_k; 154 | } 155 | 156 | 157 | int expansionObject::Gen_Scale(const int elen, const double *e, const double& b, double *h) 158 | { 159 | double Q, sum, hh, pr1, pr0, enow; 160 | int e_k, h_k; 161 | 162 | Split(b, _bh, _bl); 163 | Two_Prod_PreSplit(e[0], b, _bh, _bl, Q, hh); 164 | h_k = 0; 165 | if (hh != 0) h[h_k++] = hh; 166 | 167 | for (e_k = 1; e_k < elen; e_k++) 168 | { 169 | enow = e[e_k]; 170 | Two_Prod_PreSplit(enow, b, _bh, _bl, pr1, pr0); 171 | Two_Sum(Q, pr0, sum, hh); 172 | if (hh != 0) h[h_k++] = hh; 173 | Quick_Two_Sum(pr1, sum, Q, hh); 174 | if (hh != 0) h[h_k++] = hh; 175 | } 176 | if ((Q != 0.0) || (h_k == 0)) h[h_k++] = Q; 177 | 178 | return h_k; 179 | } 180 | 181 | 182 | void expansionObject::Two_Square(const double& a1, const double& a0, double *x) 183 | { 184 | Square(a0, _j, x[0]); 185 | _0 = a0 + a0; 186 | Two_Prod(a1, _0, _k, _1); 187 | Two_One_Sum(_k, _1, _j, _l, _2, x[1]); 188 | Square(a1, _j, _1); 189 | Two_Two_Sum(_j, _1, _l, _2, x[5], x[4], x[3], x[2]); 190 | } 191 | 192 | int expansionObject::Sub_product(const int alen, const double *a, const int blen, const double *b, double *h) 193 | { 194 | if (alen == 1) return Gen_Scale(blen, b, a[0], h); 195 | int partial = 2 * alen * blen; 196 | int allmem = 2 * (partial + blen); 197 | double ph1_p[1024]; 198 | double *ph1 = (allmem>1024) ? ((double *)malloc(allmem * sizeof(double))) : (ph1_p); 199 | double *ph2 = ph1 + partial; 200 | double *th = ph2 + partial; 201 | double *ph[2] = { ph1, ph2 }; 202 | int first = 0; 203 | int phl = Gen_Scale(blen, b, a[0], ph[0]); 204 | 205 | for (int i = 1; i < alen; i++) 206 | { 207 | int thl = Gen_Scale(blen, b, a[i], th); 208 | first = i & 1; 209 | phl = Gen_Sum(phl, ph[(i+1)&1], thl, th, ph[first]); 210 | } 211 | if (first) for (int i = 0; i < phl; i++) h[i] = ph2[i]; 212 | else for (int i = 0; i < phl; i++) h[i] = ph1[i]; 213 | if (allmem>1024) free(ph1); 214 | return phl; 215 | } 216 | 217 | 218 | int expansionObject::Gen_Product(const int alen, const double *a, const int blen, const double *b, double *h) 219 | { 220 | if (blen == 1) return Gen_Scale(alen, a, b[0], h); 221 | else if (alen < blen) return Sub_product(alen, a, blen, b, h); 222 | else return Sub_product(blen, b, alen, a, h); 223 | } 224 | 225 | 226 | double expansionObject::To_Double(const int elen, const double *e) 227 | { 228 | double Q = e[0]; 229 | for (int e_i = 1; e_i < elen; e_i++) Q += e[e_i]; 230 | return Q; 231 | } 232 | -------------------------------------------------------------------------------- /src/mixedPredicates.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * mixedPredicates.cpp * 3 | * This file is part of the TMesh_Kernel Library * 4 | * * 5 | * Authors: Marco Attene * 6 | * Copyright(C) 2012: IMATI-GE / CNR * 7 | * IMATI-GE / CNR is Consiglio Nazionale delle Ricerche * 8 | * Istituto di Matematica Applicata e Tecnologie Informatiche * 9 | * Genova (Italy) * 10 | * * 11 | * TMesh_Kernel is free software; you can redistribute it and/or modify * 12 | * it under the terms of the GNU Lesser General Public License as published * 13 | * by the Free Software Foundation; either version 3 of the License, or (at * 14 | * your option) any later version. * 15 | * * 16 | * TMesh_Kernel is distributed in the hope that it will be useful, but * 17 | * WITHOUT ANY WARRANTY; without even the implied warranty of * 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser * 19 | * General Public License for more details. * 20 | * * 21 | * You should have received a copy of the GNU Lesser General Public License * 22 | * along with TMesh_Kernel. If not, see http://www.gnu.org/licenses/. * 23 | * * 24 | ****************************************************************************/ 25 | 26 | #include 27 | 28 | #include "point.h" 29 | #ifdef USE_HYBRID_KERNEL 30 | #include "mixedPredicates.h" 31 | #endif 32 | 33 | namespace T_MESH 34 | { 35 | 36 | /**************************************************************************** 37 | * * 38 | * MIXED PREDICATES * 39 | * * 40 | ****************************************************************************/ 41 | 42 | #ifdef USE_HYBRID_KERNEL 43 | 44 | char mixedFilteredOrient2d(const PM_Rational& px, const PM_Rational& py, const PM_Rational& qx, const PM_Rational& qy, const PM_Rational& rx, const PM_Rational& ry) 45 | { 46 | unprecise_number det = unpreciseOrient2d(px, py, qx, qy, rx, ry); 47 | if (det.signIsReliable()) return det.sign(); 48 | else 49 | { 50 | // Here we already know that lazy evaluation fails. Switch to exact directly 51 | #ifdef USE_LAZY_KERNEL 52 | tmesh_fraction det = preciseOrient2d(px, py, qx, qy, rx, ry); 53 | #else 54 | bool wwu = PM_Rational::isUsingRationals(); 55 | PM_Rational::useRationals(true); 56 | PM_Rational det = ((px - rx)*(qy - ry) - (py - ry)*(qx - rx)); 57 | PM_Rational::useRationals(wwu); 58 | #endif 59 | return (det > 0) ? (1) : ((det < 0) ? (-1) : (0)); 60 | } 61 | } 62 | 63 | char mixedFilteredOrient3d(const Point3c *d, const Point3c *a, const Point3c *b, const Point3c *c) 64 | { 65 | unprecise_number det = unpreciseOrient3d(d, a, b, c); 66 | if (det.signIsReliable()) return det.sign(); 67 | else 68 | { 69 | #ifdef USE_LAZY_KERNEL 70 | tmesh_fraction det = preciseOrient3d(d, a, b, c); 71 | #else 72 | bool wwu = PM_Rational::isUsingRationals(); 73 | PM_Rational::useRationals(true); 74 | //PM_Rational det = TMESH_DETERMINANT3X3(d->x - c->x, d->y - c->y, d->z - c->z, a->x - c->x, a->y - c->y, a->z - c->z, b->x - c->x, b->y - c->y, b->z - c->z); 75 | PM_Rational det = unpreciseOrient3d(d, a, b, c); 76 | PM_Rational::useRationals(wwu); 77 | #endif 78 | return (det > 0) ? (1) : ((det < 0) ? (-1) : (0)); 79 | } 80 | } 81 | 82 | char mixedFilteredInsphere(const Point3c *pa, const Point3c *pb, const Point3c *pc, const Point3c *pd, const Point3c *pe) 83 | { 84 | unprecise_number det = unpreciseInsphere(pa, pb, pc, pd, pe); 85 | if (det.signIsReliable()) return det.sign(); 86 | else 87 | { 88 | #ifdef USE_LAZY_KERNEL 89 | tmesh_fraction det = preciseInsphere(pa, pb, pc, pd, pe); 90 | #else 91 | bool wwu = PM_Rational::isUsingRationals(); 92 | PM_Rational::useRationals(true); 93 | coord det = unpreciseInsphere(pa, pb, pc, pd, pe); 94 | PM_Rational::useRationals(wwu); 95 | #endif 96 | return (det > 0) ? (1) : ((det < 0) ? (-1) : (0)); 97 | } 98 | } 99 | 100 | char mixedFilteredInCircle3D(const Point3c *pa, const Point3c *pb, const Point3c *pc, const Point3c *pd) 101 | { 102 | unprecise_number det = unpreciseInCircle3D(pa, pb, pc, pd); 103 | if (det.signIsReliable()) return det.sign(); 104 | else 105 | { 106 | #ifdef USE_LAZY_KERNEL 107 | tmesh_fraction det = preciseInCircle3D(pa, pb, pc, pd); 108 | #else 109 | bool wwu = PM_Rational::isUsingRationals(); 110 | PM_Rational::useRationals(true); 111 | coord det = unpreciseInCircle3D(pa, pb, pc, pd); 112 | PM_Rational::useRationals(wwu); 113 | #endif 114 | return (det > 0) ? (1) : ((det < 0) ? (-1) : (0)); 115 | } 116 | } 117 | 118 | 119 | char orient2D(const PM_Rational& px, const PM_Rational& py, const PM_Rational& qx, const PM_Rational& qy, const PM_Rational& rx, const PM_Rational& ry) 120 | { 121 | if (px.isOfDoubleType() && py.isOfDoubleType() && qx.isOfDoubleType() && qy.isOfDoubleType() && rx.isOfDoubleType() && ry.isOfDoubleType()) 122 | { 123 | double pqr[6]; 124 | pqr[0] = px.getDVal(); pqr[1] = py.getDVal(); 125 | pqr[2] = qx.getDVal(); pqr[3] = qy.getDVal(); 126 | pqr[4] = rx.getDVal(); pqr[5] = ry.getDVal(); 127 | 128 | unsigned int prevround = getFPURoundingMode(); 129 | setFPUModeToRoundNEAR(); 130 | double det = TMesh::tri_orientation(pqr, pqr + 2, pqr + 4); 131 | setFPURoundingMode(prevround); 132 | 133 | return (det > 0) ? (1) : ((det < 0) ? (-1) : (0)); 134 | } 135 | else return mixedFilteredOrient2d(px, py, qx, qy, rx, ry); 136 | } 137 | 138 | char orient3D(const Point3c *t, const Point3c *a, const Point3c *b, const Point3c *c) 139 | { 140 | if (a->x.isOfDoubleType() && a->y.isOfDoubleType() && a->z.isOfDoubleType() && 141 | t->x.isOfDoubleType() && t->y.isOfDoubleType() && t->z.isOfDoubleType() && 142 | b->x.isOfDoubleType() && b->y.isOfDoubleType() && b->z.isOfDoubleType() && 143 | c->x.isOfDoubleType() && c->y.isOfDoubleType() && c->z.isOfDoubleType()) 144 | { 145 | double p1[3], p2[3], p3[3], p4[3]; 146 | p1[0] = (t->x).getDVal(); p1[1] = (t->y).getDVal(); p1[2] = (t->z).getDVal(); 147 | p2[0] = (a->x).getDVal(); p2[1] = (a->y).getDVal(); p2[2] = (a->z).getDVal(); 148 | p3[0] = (b->x).getDVal(); p3[1] = (b->y).getDVal(); p3[2] = (b->z).getDVal(); 149 | p4[0] = (c->x).getDVal(); p4[1] = (c->y).getDVal(); p4[2] = (c->z).getDVal(); 150 | 151 | unsigned int prevround = getFPURoundingMode(); 152 | setFPUModeToRoundNEAR(); 153 | double det = TMesh::tet_orientation(p1, p2, p3, p4); 154 | setFPURoundingMode(prevround); 155 | 156 | return (det > 0) ? (1) : ((det < 0) ? (-1) : (0)); 157 | } 158 | else return mixedFilteredOrient3d(t, a, b, c); 159 | } 160 | 161 | char inSphere3D(const Point3c *pa, const Point3c *pb, const Point3c *pc, const Point3c *pd, const Point3c *pe) 162 | { 163 | if (pa->x.isOfDoubleType() && pa->y.isOfDoubleType() && pa->z.isOfDoubleType() && 164 | pe->x.isOfDoubleType() && pe->y.isOfDoubleType() && pe->z.isOfDoubleType() && 165 | pd->x.isOfDoubleType() && pd->y.isOfDoubleType() && pd->z.isOfDoubleType() && 166 | pb->x.isOfDoubleType() && pb->y.isOfDoubleType() && pb->z.isOfDoubleType() && 167 | pc->x.isOfDoubleType() && pc->y.isOfDoubleType() && pc->z.isOfDoubleType()) 168 | { 169 | double p1[3], p2[3], p3[3], p4[3], p5[3]; 170 | p1[0] = (pa->x).getDVal(); p1[1] = (pa->y).getDVal(); p1[2] = (pa->z).getDVal(); 171 | p2[0] = (pb->x).getDVal(); p2[1] = (pb->y).getDVal(); p2[2] = (pb->z).getDVal(); 172 | p3[0] = (pc->x).getDVal(); p3[1] = (pc->y).getDVal(); p3[2] = (pc->z).getDVal(); 173 | p4[0] = (pd->x).getDVal(); p4[1] = (pd->y).getDVal(); p4[2] = (pd->z).getDVal(); 174 | p5[0] = (pe->x).getDVal(); p5[1] = (pe->y).getDVal(); p5[2] = (pe->z).getDVal(); 175 | 176 | unsigned int prevround = getFPURoundingMode(); 177 | setFPUModeToRoundNEAR(); 178 | double det = TMesh::insphere(p1, p2, p3, p4, p5); 179 | setFPURoundingMode(prevround); 180 | 181 | return (det > 0) ? (1) : ((det < 0) ? (-1) : (0)); 182 | } else return mixedFilteredInsphere(pa, pb, pc, pd, pe); 183 | } 184 | 185 | 186 | char inCircle3D(const Point3c *pa, const Point3c *pb, const Point3c *pc, const Point3c *pd) 187 | { 188 | if (pa->x.isOfDoubleType() && pa->y.isOfDoubleType() && pa->z.isOfDoubleType() && 189 | pd->x.isOfDoubleType() && pd->y.isOfDoubleType() && pd->z.isOfDoubleType() && 190 | pb->x.isOfDoubleType() && pb->y.isOfDoubleType() && pb->z.isOfDoubleType() && 191 | pc->x.isOfDoubleType() && pc->y.isOfDoubleType() && pc->z.isOfDoubleType()) 192 | { 193 | double p1[3], p2[3], p3[3], p4[3]; 194 | p1[0] = (pa->x).getDVal(); p1[1] = (pa->y).getDVal(); p1[2] = (pa->z).getDVal(); 195 | p2[0] = (pb->x).getDVal(); p2[1] = (pb->y).getDVal(); p2[2] = (pb->z).getDVal(); 196 | p3[0] = (pc->x).getDVal(); p3[1] = (pc->y).getDVal(); p3[2] = (pc->z).getDVal(); 197 | p4[0] = (pd->x).getDVal(); p4[1] = (pd->y).getDVal(); p4[2] = (pd->z).getDVal(); 198 | 199 | unsigned int prevround = getFPURoundingMode(); 200 | setFPUModeToRoundNEAR(); 201 | double det = TMesh::incircle3D(p1, p2, p3, p4); 202 | setFPURoundingMode(prevround); 203 | 204 | return (det > 0) ? (1) : ((det < 0) ? (-1) : (0)); 205 | } else return mixedFilteredInCircle3D(pa, pb, pc, pd); 206 | } 207 | 208 | #else 209 | 210 | char orient2D(const PM_Rational& px, const PM_Rational& py, const PM_Rational& qx, const PM_Rational& qy, const PM_Rational& rx, const PM_Rational& ry) 211 | { 212 | // return ((px - rx)*(qy - ry) - (py - ry)*(qx - rx)); 213 | 214 | double pqr[6]; 215 | pqr[0] = TMESH_TO_DOUBLE(px); pqr[1] = TMESH_TO_DOUBLE(py); 216 | pqr[2] = TMESH_TO_DOUBLE(qx); pqr[3] = TMESH_TO_DOUBLE(qy); 217 | pqr[4] = TMESH_TO_DOUBLE(rx); pqr[5] = TMESH_TO_DOUBLE(ry); 218 | PM_Rational det = TMesh::tri_orientation(pqr, pqr + 2, pqr + 4); 219 | return (det > 0) ? (1) : ((det < 0) ? (-1) : (0)); 220 | } 221 | 222 | char orient3D(const Point3c *t, const Point3c *a, const Point3c *b, const Point3c *c) 223 | { 224 | // return TMESH_DETERMINANT3X3(t->x - c->x, t->y - c->y, t->z - c->z, a->x - c->x, a->y - c->y, a->z - c->z, b->x - c->x, b->y - c->y, b->z - c->z); 225 | 226 | double p1[3], p2[3], p3[3], p4[3]; 227 | p1[0] = TMESH_TO_DOUBLE(t->x); p1[1] = TMESH_TO_DOUBLE(t->y); p1[2] = TMESH_TO_DOUBLE(t->z); 228 | p2[0] = TMESH_TO_DOUBLE(a->x); p2[1] = TMESH_TO_DOUBLE(a->y); p2[2] = TMESH_TO_DOUBLE(a->z); 229 | p3[0] = TMESH_TO_DOUBLE(b->x); p3[1] = TMESH_TO_DOUBLE(b->y); p3[2] = TMESH_TO_DOUBLE(b->z); 230 | p4[0] = TMESH_TO_DOUBLE(c->x); p4[1] = TMESH_TO_DOUBLE(c->y); p4[2] = TMESH_TO_DOUBLE(c->z); 231 | double det = TMesh::tet_orientation(p1, p2, p3, p4); 232 | return (det > 0) ? (1) : ((det < 0) ? (-1) : (0)); 233 | } 234 | 235 | char inSphere3D(const Point3c *pa, const Point3c *pb, const Point3c *pc, const Point3c *pd, const Point3c *pe) 236 | { 237 | double p1[3], p2[3], p3[3], p4[3], p5[3]; 238 | p1[0] = TMESH_TO_DOUBLE(pa->x); p1[1] = TMESH_TO_DOUBLE(pa->y); p1[2] = TMESH_TO_DOUBLE(pa->z); 239 | p2[0] = TMESH_TO_DOUBLE(pb->x); p2[1] = TMESH_TO_DOUBLE(pb->y); p2[2] = TMESH_TO_DOUBLE(pb->z); 240 | p3[0] = TMESH_TO_DOUBLE(pc->x); p3[1] = TMESH_TO_DOUBLE(pc->y); p3[2] = TMESH_TO_DOUBLE(pc->z); 241 | p4[0] = TMESH_TO_DOUBLE(pd->x); p4[1] = TMESH_TO_DOUBLE(pd->y); p4[2] = TMESH_TO_DOUBLE(pd->z); 242 | p5[0] = TMESH_TO_DOUBLE(pe->x); p5[1] = TMESH_TO_DOUBLE(pe->y); p5[2] = TMESH_TO_DOUBLE(pe->z); 243 | double det = TMesh::insphere(p1, p2, p3, p4, p5); 244 | return (det > 0) ? (1) : ((det < 0) ? (-1) : (0)); 245 | } 246 | 247 | char inCircle3D(const Point3c *pa, const Point3c *pb, const Point3c *pc, const Point3c *pd) 248 | { 249 | double p1[3], p2[3], p3[3], p4[3]; 250 | p1[0] = TMESH_TO_DOUBLE(pa->x); p1[1] = TMESH_TO_DOUBLE(pa->y); p1[2] = TMESH_TO_DOUBLE(pa->z); 251 | p2[0] = TMESH_TO_DOUBLE(pb->x); p2[1] = TMESH_TO_DOUBLE(pb->y); p2[2] = TMESH_TO_DOUBLE(pb->z); 252 | p3[0] = TMESH_TO_DOUBLE(pc->x); p3[1] = TMESH_TO_DOUBLE(pc->y); p3[2] = TMESH_TO_DOUBLE(pc->z); 253 | p4[0] = TMESH_TO_DOUBLE(pd->x); p4[1] = TMESH_TO_DOUBLE(pd->y); p4[2] = TMESH_TO_DOUBLE(pd->z); 254 | double det = TMesh::incircle3D(p1, p2, p3, p4); 255 | return (det > 0) ? (1) : ((det < 0) ? (-1) : (0)); 256 | } 257 | 258 | #endif 259 | 260 | } //namespace T_MESH 261 | -------------------------------------------------------------------------------- /src/point.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * point.cpp * 3 | * This file is part of the TMesh_Kernel Library * 4 | * * 5 | * Authors: Marco Attene * 6 | * Copyright(C) 2012: IMATI-GE / CNR * 7 | * IMATI-GE / CNR is Consiglio Nazionale delle Ricerche * 8 | * Istituto di Matematica Applicata e Tecnologie Informatiche * 9 | * Genova (Italy) * 10 | * * 11 | * TMesh_Kernel is free software; you can redistribute it and/or modify * 12 | * it under the terms of the GNU Lesser General Public License as published * 13 | * by the Free Software Foundation; either version 3 of the License, or (at * 14 | * your option) any later version. * 15 | * * 16 | * TMesh_Kernel is distributed in the hope that it will be useful, but * 17 | * WITHOUT ANY WARRANTY; without even the implied warranty of * 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser * 19 | * General Public License for more details. * 20 | * * 21 | * You should have received a copy of the GNU Lesser General Public License * 22 | * along with TMesh_Kernel. If not, see http://www.gnu.org/licenses/. * 23 | * * 24 | ****************************************************************************/ 25 | 26 | #include "point.h" 27 | #include 28 | #include 29 | #include 30 | 31 | namespace T_MESH 32 | { 33 | 34 | const Point3c INFINITE_POINT(TMESH_INFINITY, TMESH_INFINITY, TMESH_INFINITY); 35 | 36 | //////// Lexicographic Point3c comparison ////////// 37 | 38 | // This can be used with std::sort() 39 | bool Point3c::operator<(const Point3c& s) const 40 | { 41 | if (xs.x) return false; 42 | if (ys.y) return false; 43 | if (zx, A->y, B->x, B->y) != 0) return true; 88 | if (orient2D(y, z, A->y, A->z, B->y, B->z) != 0) return true; 89 | if (orient2D(z, x, A->z, A->x, B->z, B->x) != 0) return true; 90 | 91 | return false; 92 | } 93 | 94 | bool Point3c::exactSameSideOnPlane(const Point3c *Q, const Point3c *A, const Point3c *B) const 95 | { 96 | char o1, o2; 97 | 98 | o1 = orient2D(x, y, A->x, A->y, B->x, B->y); 99 | o2 = orient2D(Q->x, Q->y, A->x, A->y, B->x, B->y); 100 | if (o1 != o2) return false; 101 | 102 | o1 = orient2D(y, z, A->y, A->z, B->y, B->z); 103 | o2 = orient2D(Q->y, Q->z, A->y, A->z, B->y, B->z); 104 | if (o1 != o2) return false; 105 | 106 | o1 = orient2D(z, x, A->z, A->x, B->z, B->x); 107 | o2 = orient2D(Q->z, Q->x, A->z, A->x, B->z, B->x); 108 | if (o1 != o2) return false; 109 | 110 | return true; 111 | } 112 | 113 | 114 | ////////////////////////////////////////////////////////////////// 115 | // 116 | // Basic predicates of type 'pointIn' 117 | // 118 | ////////////////////////////////////////////////////////////////// 119 | 120 | // Returns true if 'p' is a point of the segment v1-v2 (endpoints excluded) 121 | bool Point3c::pointInInnerSegment(const Point3c *p, const Point3c *v1, const Point3c *v2) 122 | { 123 | if (!p->exactMisalignment(v1, v2)) // Segment and point aligned 124 | { 125 | if (v1->x < v2->x && v1->x < p->x && p->x < v2->x) return true; 126 | if (v1->y < v2->y && v1->y < p->y && p->y < v2->y) return true; 127 | if (v1->z < v2->z && v1->z < p->z && p->z < v2->z) return true; 128 | if (v1->x > v2->x && v1->x > p->x && p->x > v2->x) return true; 129 | if (v1->y > v2->y && v1->y > p->y && p->y > v2->y) return true; 130 | if (v1->z > v2->z && v1->z > p->z && p->z > v2->z) return true; 131 | } 132 | return false; 133 | } 134 | 135 | // Returns true if 'p' is a point of the segment v1-v2 (endpoints included) 136 | bool Point3c::pointInSegment(const Point3c *p, const Point3c *v1, const Point3c *v2) 137 | { 138 | return ((*p) == (*(v1)) || (*p) == (*(v2)) || Point3c::pointInInnerSegment(p, v1, v2)); 139 | } 140 | 141 | // Returns true if the coplanar point 'p' is in the inner area of 't'. 142 | // Undetermined if p and t are not coplanar. 143 | bool Point3c::pointInInnerTriangle(const Point3c *p, const Point3c *v1, const Point3c *v2, const Point3c *v3) 144 | { 145 | char o1, o2, oo2, oo4, oo6; 146 | 147 | o1 = orient2D(p->x, p->y, v2->x, v2->y, v3->x, v3->y); 148 | o2 = oo2 = orient2D(v1->x, v1->y, v2->x, v2->y, v3->x, v3->y); 149 | if (o1 != o2) return false; 150 | 151 | o1 = orient2D(p->y, p->z, v2->y, v2->z, v3->y, v3->z); 152 | o2 = oo4 = orient2D(v1->y, v1->z, v2->y, v2->z, v3->y, v3->z); 153 | if (o1 != o2) return false; 154 | 155 | o1 = orient2D(p->z, p->x, v2->z, v2->x, v3->z, v3->x); 156 | o2 = oo6 = orient2D(v1->z, v1->x, v2->z, v2->x, v3->z, v3->x); 157 | if (o1 != o2) return false; 158 | 159 | o1 = orient2D(p->x, p->y, v3->x, v3->y, v1->x, v1->y); 160 | o2 = oo2; 161 | if (o1 != o2) return false; 162 | 163 | o1 = orient2D(p->y, p->z, v3->y, v3->z, v1->y, v1->z); 164 | o2 = oo4; 165 | if (o1 != o2) return false; 166 | 167 | o1 = orient2D(p->z, p->x, v3->z, v3->x, v1->z, v1->x); 168 | o2 = oo6; 169 | if (o1 != o2) return false; 170 | 171 | o1 = orient2D(p->x, p->y, v1->x, v1->y, v2->x, v2->y); 172 | o2 = oo2; 173 | if (o1 != o2) return false; 174 | 175 | o1 = orient2D(p->y, p->z, v1->y, v1->z, v2->y, v2->z); 176 | o2 = oo4; 177 | if (o1 != o2) return false; 178 | 179 | o1 = orient2D(p->z, p->x, v1->z, v1->x, v2->z, v2->x); 180 | o2 = oo6; 181 | if (o1 != o2) return false; 182 | 183 | return true; 184 | } 185 | 186 | // Returns true if the coplanar point 'p' is either in the inner area of 187 | // 't' or on its border. Undetermined if p and t are not coplanar. 188 | bool Point3c::pointInTriangle(const Point3c *p, const Point3c *v1, const Point3c *v2, const Point3c *v3) 189 | { 190 | if (Point3c::pointInSegment(p, v1, v2)) return true; 191 | else if (Point3c::pointInSegment(p, v2, v3)) return true; 192 | else if (Point3c::pointInSegment(p, v3, v1)) return true; 193 | else return Point3c::pointInInnerTriangle(p, v1, v2, v3); 194 | } 195 | 196 | 197 | ////////////////////////////////////////////////////////////////// 198 | // 199 | // Basic predicates of type 'segmentIntersects' 200 | // 201 | ////////////////////////////////////////////////////////////////// 202 | 203 | // Returns true if the interior of (p1-p2) properly intersects the interior of (sp1-sp2). 204 | // Collinear overlapping segments are not considered to be properly intersecting. 205 | bool Point3c::innerSegmentsCross(const Point3c& p1, const Point3c& p2, const Point3c& sp1, const Point3c& sp2) 206 | { 207 | if (p1 == sp1 || p1 == sp2 || p2 == sp1 || p2 == sp2) return false; // Endpoints cannot coincide 208 | if (p1.exactOrientation(&p2, &sp1, &sp2) != 0) return false; // Must be coplanar 209 | if (p1.exactSameSideOnPlane(&p2, &sp1, &sp2) || sp1.exactSameSideOnPlane(&sp2, &p1, &p2)) return false; // Cannot be either on one side of the other 210 | 211 | if (orient2D(p1.x, p1.y, p2.x, p2.y, sp1.x, sp1.y) != 0) return true; 212 | if (orient2D(sp2.x, sp2.y, p2.x, p2.y, sp1.x, sp1.y) != 0) return true; 213 | if (orient2D(p1.y, p1.z, p2.y, p2.z, sp1.y, sp1.z) != 0) return true; 214 | if (orient2D(sp2.y, sp2.z, p2.y, p2.z, sp1.y, sp1.z) != 0) return true; 215 | if (orient2D(p1.z, p1.x, p2.z, p2.x, sp1.z, sp1.x) != 0) return true; 216 | if (orient2D(sp2.z, sp2.x, p2.z, p2.x, sp1.z, sp1.x) != 0) return true; 217 | return false; 218 | } 219 | 220 | // true if (p1-p2) properly intersects (sp1-sp2) at any point (endpoints included). 221 | // Collinear overlapping segments are not considered to be properly intersecting. 222 | bool Point3c::segmentsIntersect(const Point3c *p1, const Point3c *p2, const Point3c *sp1, const Point3c *sp2) 223 | { 224 | return (p1->exactOrientation(p2, sp1, sp2) == 0 && !p1->exactSameSideOnPlane(p2, sp1, sp2) && !sp1->exactSameSideOnPlane(sp2, p1, p2)); 225 | } 226 | 227 | bool Point3c::segmentProperlyIntersectsTriangle(const Point3c *s1, const Point3c *s2, const Point3c *v1, const Point3c *v2, const Point3c *v3) 228 | { 229 | char o1, o2, o3; 230 | 231 | coord mx = MIN(s1->x, s2->x); 232 | if (v1->x < mx && v2->x < mx && v3->x < mx) return false; 233 | mx = MAX(s1->x, s2->x); 234 | if (v1->x > mx && v2->x > mx && v3->x > mx) return false; 235 | mx = MIN(s1->y, s2->y); 236 | if (v1->y < mx && v2->y < mx && v3->y < mx) return false; 237 | mx = MAX(s1->y, s2->y); 238 | if (v1->y > mx && v2->y > mx && v3->y > mx) return false; 239 | mx = MIN(s1->z, s2->z); 240 | if (v1->z < mx && v2->z < mx && v3->z < mx) return false; 241 | mx = MAX(s1->z, s2->z); 242 | if (v1->z > mx && v2->z > mx && v3->z > mx) return false; 243 | 244 | if ((o1 = s1->exactOrientation(v1, v2, v3)) == 0) return false; 245 | if ((o2 = s2->exactOrientation(v1, v2, v3)) == 0) return false; 246 | if ((o1>0 && o2>0) || (o1<0 && o2<0)) return false; 247 | 248 | // Only one above and one below here... 249 | if ((o1 = s1->exactOrientation(s2, v1, v2)) == 0) return false; 250 | if ((o2 = s1->exactOrientation(s2, v2, v3)) == 0) return false; 251 | if ((o1>0 && o2<0) || (o1<0 && o2>0)) return false; 252 | if ((o3 = s1->exactOrientation(s2, v3, v1)) == 0) return false; 253 | if ((o1>0 && o3<0) || (o1<0 && o3>0)) return false; 254 | if ((o2>0 && o3<0) || (o2<0 && o3>0)) return false; 255 | return true; 256 | } 257 | 258 | bool Point3c::segmentIntersectsTriangle(const Point3c *s1, const Point3c *s2, const Point3c *v1, const Point3c *v2, const Point3c *v3) 259 | { 260 | char o1, o2, o3; 261 | 262 | coord mx = MIN(s1->x, s2->x); 263 | if (v1->x < mx && v2->x < mx && v3->x < mx) return false; 264 | mx = MAX(s1->x, s2->x); 265 | if (v1->x > mx && v2->x > mx && v3->x > mx) return false; 266 | mx = MIN(s1->y, s2->y); 267 | if (v1->y < mx && v2->y < mx && v3->y < mx) return false; 268 | mx = MAX(s1->y, s2->y); 269 | if (v1->y > mx && v2->y > mx && v3->y > mx) return false; 270 | mx = MIN(s1->z, s2->z); 271 | if (v1->z < mx && v2->z < mx && v3->z < mx) return false; 272 | mx = MAX(s1->z, s2->z); 273 | if (v1->z > mx && v2->z > mx && v3->z > mx) return false; 274 | 275 | o1 = s1->exactOrientation(v1, v2, v3); 276 | o2 = s2->exactOrientation(v1, v2, v3); 277 | if (o1 == 0 && o2 == 0) 278 | { 279 | if (!s1->exactSameSideOnPlane(s2, v1, v2) && !v1->exactSameSideOnPlane(v2, s1, s2)) return true; 280 | if (!s1->exactSameSideOnPlane(s2, v2, v3) && !v2->exactSameSideOnPlane(v3, s1, s2)) return true; 281 | if (!s1->exactSameSideOnPlane(s2, v3, v1) && !v3->exactSameSideOnPlane(v1, s1, s2)) return true; 282 | if (Point3c::pointInInnerTriangle(s1, v1, v2, v3) && Point3c::pointInInnerTriangle(s2, v1, v2, v3)) return true; 283 | return false; 284 | } 285 | 286 | if ((o1>0 && o2>0) || (o1<0 && o2<0)) return false; // s1 and s2 are both above/below v1,v2,v3 287 | o1 = s1->exactOrientation(s2, v1, v2); 288 | o2 = s1->exactOrientation(s2, v2, v3); 289 | if ((o1>0 && o2<0) || (o1<0 && o2>0)) return false; 290 | o3 = s1->exactOrientation(s2, v3, v1); 291 | if ((o1>0 && o3<0) || (o1<0 && o3>0)) return false; 292 | if ((o2>0 && o3<0) || (o2<0 && o3>0)) return false; 293 | return true; 294 | } 295 | 296 | bool Point3c::segmentIntersectsTriangle(const Point3c *s1, const Point3c *s2, const Point3c *v1, const Point3c *v2, const Point3c *v3, char oo1, char oo2) 297 | { 298 | // In this case the fast reject by bounding box appears to be a disadvantage ... 299 | if (oo1 == 0 && oo2 == 0) 300 | { 301 | if (!s1->exactSameSideOnPlane(s2, v1, v2) && !v1->exactSameSideOnPlane(v2, s1, s2)) return true; 302 | if (!s1->exactSameSideOnPlane(s2, v2, v3) && !v2->exactSameSideOnPlane(v3, s1, s2)) return true; 303 | if (!s1->exactSameSideOnPlane(s2, v3, v1) && !v3->exactSameSideOnPlane(v1, s1, s2)) return true; 304 | if (Point3c::pointInInnerTriangle(s1, v1, v2, v3) && Point3c::pointInInnerTriangle(s2, v1, v2, v3)) return true; 305 | return false; 306 | } 307 | 308 | if ((oo1>0 && oo2>0) || (oo1<0 && oo2<0)) return false; // s1 and s2 are both above/below v1,v2,v3 309 | char o1, o2, o3; 310 | o1 = s1->exactOrientation(s2, v1, v2); 311 | o2 = s1->exactOrientation(s2, v2, v3); 312 | if ((o1>0 && o2<0) || (o1<0 && o2>0)) return false; 313 | o3 = s1->exactOrientation(s2, v3, v1); 314 | if ((o1>0 && o3<0) || (o1<0 && o3>0)) return false; 315 | if ((o2>0 && o3<0) || (o2<0 && o3>0)) return false; 316 | return true; 317 | } 318 | 319 | 320 | 321 | // Returns the point of intersection between the two lines defined by (p,q) and (r,s) respectively 322 | // Return INFINITE_POINT is lines do not intersect or if p==q or r==s 323 | Point3c Point3c::lineLineIntersection(const Point3c& p, const Point3c& q, const Point3c& r, const Point3c& s) 324 | { 325 | Point3c da(q - p), db(s - r), dc(r - p); 326 | Point3c dab(da&db); 327 | 328 | if (dab.isNull()) return INFINITE_POINT; // parallel 329 | if (TMESH_IS_NONZERO(dc*dab)) return INFINITE_POINT; // skew 330 | 331 | return p + (da*(((dc&db)*dab) / (dab*dab))); 332 | } 333 | 334 | Point3c Point3c::tmpExact_lineLineIntersection(const Point3c& p, const Point3c& q, const Point3c& r, const Point3c& s) 335 | { 336 | bool ps = TMesh::useRationals(); 337 | Point3c res = lineLineIntersection(p, q, r, s); 338 | TMesh::useRationals(ps); 339 | return res; 340 | } 341 | 342 | // Returns the point of intersection between the line for (p,q) and the plane for (r,s,t) 343 | // Returns INFINITE_POINT in case of parallelism 344 | Point3c Point3c::linePlaneIntersection(const Point3c& p, const Point3c& q, const Point3c& r, const Point3c& s, const Point3c& t) 345 | { 346 | coord a11(p.x - q.x), a12(p.y - q.y), a13(p.z - q.z); 347 | coord a21(s.x - r.x), a22(s.y - r.y), a23(s.z - r.z); 348 | coord a31(t.x - r.x), a32(t.y - r.y), a33(t.z - r.z); 349 | coord a2233(a22*a33 - a23*a32); 350 | coord a2133(a21*a33 - a23*a31); 351 | coord a2132(a21*a32 - a22*a31); 352 | coord den(a11*a2233 - a12*a2133 + a13*a2132); 353 | if (TMESH_IS_ZERO(den)) return INFINITE_POINT; 354 | coord num(((p.y - r.y)*(a2133) - (p.x - r.x)*(a2233) - (p.z - r.z)*(a2132))/den); 355 | return Point3c(p.x + a11*num, p.y + a12*num, p.z + a13*num); 356 | } 357 | 358 | Point3c Point3c::tmpExact_linePlaneIntersection(const Point3c& p, const Point3c& q, const Point3c& r, const Point3c& s, const Point3c& t) 359 | { 360 | bool ps = TMesh::useRationals(); 361 | Point3c res = linePlaneIntersection(p, q, r, s, t); 362 | TMesh::useRationals(ps); 363 | return res; 364 | } 365 | 366 | // Returns the point of intersection between the line for (v1,v2) and the plane for 'v0' with directional vector 'd' 367 | // Returns INFINITE_POINT in case of parallelism 368 | Point3c Point3c::linePlaneIntersection(const Point3c& v1, const Point3c& v2, const Point3c& v0, const Point3c& d) 369 | { 370 | Point3c v21(v2 - v1); 371 | coord den(d*v21); 372 | if (TMESH_IS_ZERO(den)) return INFINITE_POINT; 373 | else return v1 + (v21*((d*(v0 - v1)) / den)); 374 | } 375 | 376 | Point3c Point3c::tmpExact_linePlaneIntersection(const Point3c& v1, const Point3c& v2, const Point3c& v0, const Point3c& d) 377 | { 378 | bool ps = TMesh::useRationals(); 379 | Point3c res = linePlaneIntersection(v1, v2, v0, d); 380 | TMesh::useRationals(ps); 381 | return res; 382 | } 383 | 384 | Point3c Point3c::threePlanesIntersection(const Point3c& v1, const Point3c& v2, const Point3c& v3, 385 | const Point3c& w1, const Point3c& w2, const Point3c& w3, 386 | const Point3c& u1, const Point3c& u2, const Point3c& u3) 387 | { 388 | Point3c nv((v2 - v1)&(v3 - v2)); 389 | Point3c nw((w2 - w1)&(w3 - w2)); 390 | Point3c nu((u2 - u1)&(u3 - u2)); 391 | return Point3c(nv*v1, nw*w1, nu*u1).linearSystem(nv, nw, nu); 392 | } 393 | 394 | Point3c Point3c::tmpExact_threePlanesIntersection(const Point3c& v1, const Point3c& v2, const Point3c& v3, 395 | const Point3c& w1, const Point3c& w2, const Point3c& w3, 396 | const Point3c& u1, const Point3c& u2, const Point3c& u3) 397 | { 398 | bool ps = TMesh::useRationals(); 399 | Point3c res = threePlanesIntersection(v1, v2, v3, w1, w2, w3, u1, u2, u3); 400 | TMesh::useRationals(ps); 401 | return res; 402 | } 403 | 404 | coord Point3c::squaredDistanceFromLine(const Point3c *x1, const Point3c *x2) const 405 | { 406 | Point3c x21((*x2) - (*x1)); 407 | if (x21.isNull()) return TMESH_INFINITY; 408 | Point3c x10((*x1) - (*this)); 409 | x10 = x21&x10; 410 | return (x10*x10) / (x21*x21); 411 | } 412 | 413 | coord Point3c::squaredDistanceFromPlane(const Point3c& dirver, const Point3c& app_point) const 414 | { 415 | coord CA2 = dirver*dirver; 416 | 417 | if (TMESH_IS_ZERO(CA2)) return TMESH_INFINITY; 418 | coord d = (dirver*(*this)) - (dirver*(app_point)); 419 | 420 | return (d*d) / CA2; 421 | } 422 | 423 | 424 | //// Computes the closest points of the two lines 'this'-v1 and p1-p2 //// 425 | //// Returns FALSE if the lines are parallel. //// 426 | 427 | bool Point3c::closestPoints(const Point3c *v1, const Point3c *p1, const Point3c *p2, Point3c *ptOnThis, Point3c *ptOnLine2) const 428 | { 429 | Point3c u = (*v1) - (*this); 430 | if (u.isNull()) return false; 431 | Point3c v = (*p2) - (*p1); 432 | if (v.isNull()) return false; 433 | 434 | coord A = u*u; 435 | coord B = u*v; 436 | coord C = v*v; 437 | coord denom = (A*C) - (B*B); 438 | if (TMESH_IS_ZERO(denom)) return false; // Lines are parallel 439 | 440 | Point3c w0 = (*this) - (*p1); 441 | coord D = u*w0; 442 | coord E = v*w0; 443 | coord s = (B*E - C*D) / denom; 444 | coord t = (A*E - B*D) / denom; 445 | 446 | *ptOnThis = (*this) + (u*s); 447 | *ptOnLine2 = (*p1) + (v*t); 448 | 449 | return true; 450 | } 451 | 452 | 453 | 454 | 455 | 456 | //////////////// Normalization ///////////////////////// 457 | 458 | Point3c& Point3c::normalize() 459 | { 460 | coord l = length(); 461 | if (l == 0) TMesh::error("normalize : Trying to normalize a null vector !\n"); 462 | operator/=(l); 463 | return *this; 464 | } 465 | 466 | 467 | //////////////////// Point3c rotation //////////////////// 468 | /////////// 'ang' radians CCW around 'axis' //////////// 469 | 470 | void Point3c::rotate(const Point3c& a, const double& ang) 471 | { 472 | double l, q[4], m[3][3]; 473 | if ((l = a.length())==0.0) return; 474 | l = sin(ang/2.0)/l; 475 | 476 | q[0] = TMESH_TO_DOUBLE(a.x)*l; 477 | q[1] = TMESH_TO_DOUBLE(a.y)*l; 478 | q[2] = TMESH_TO_DOUBLE(a.z)*l; 479 | q[3] = cos(ang/2.0); 480 | 481 | m[0][0] = 1.0 - (q[1]*q[1] + q[2]*q[2])*2.0; 482 | m[0][1] = (q[0] * q[1] + q[2] * q[3])*2.0; 483 | m[0][2] = (q[2] * q[0] - q[1] * q[3])*2.0; 484 | 485 | m[1][0] = (q[0] * q[1] - q[2] * q[3])*2.0; 486 | m[1][1] = 1.0 - (q[2] * q[2] + q[0] * q[0])*2.0; 487 | m[1][2] = (q[1] * q[2] + q[0] * q[3])*2.0; 488 | 489 | m[2][0] = (q[2] * q[0] + q[1] * q[3])*2.0; 490 | m[2][1] = (q[1] * q[2] - q[0] * q[3])*2.0; 491 | m[2][2] = 1.0 - (q[1] * q[1] + q[0] * q[0])*2.0; 492 | 493 | q[0] = TMESH_TO_DOUBLE(x); q[1] = TMESH_TO_DOUBLE(y); q[2] = TMESH_TO_DOUBLE(z); 494 | x = m[0][0]*q[0] + m[1][0]*q[1] + m[2][0]*q[2]; 495 | y = m[0][1]*q[0] + m[1][1]*q[1] + m[2][1]*q[2]; 496 | z = m[0][2]*q[0] + m[1][2]*q[1] + m[2][2]*q[2]; 497 | } 498 | 499 | 500 | /////////// Distance from the line passing through A and B //////// 501 | 502 | double Point3c::distanceFromLine(const Point3c *A, const Point3c *B) const 503 | { 504 | return sqrt(TMESH_TO_DOUBLE(squaredDistanceFromLine(A, B))); 505 | } 506 | 507 | 508 | /////////////////// Distance from a line /////////////////////// 509 | //// 'cc' is initialized as the point of the line whose //// 510 | //// distance from 'this' is minimum. //// 511 | 512 | double Point3c::distanceFromLine(const Point3c *A, const Point3c *B, Point3c *cc) const 513 | { 514 | Point3c AP((*A)-(*this)); 515 | if (AP.isNull()) { cc->setValue(A); return 0.0; } 516 | 517 | Point3c BP((*B) - (*this)); 518 | if (BP.isNull()) { cc->setValue(B); return 0.0; } 519 | 520 | Point3c AB((*A) - (*B)); 521 | coord t = (AB*AB); 522 | if (t == 0.0) TMESH_INFINITY; 523 | else t = (AP*AB)/(-t); 524 | 525 | cc->setValue((AB*t) + A); 526 | return distanceFromLine(A,B); 527 | } 528 | 529 | 530 | ////////////// Distance from a segment ///////////////// 531 | 532 | double Point3c::distanceFromEdge(const Point3c *A, const Point3c *B) const 533 | { 534 | Point3c AP((*A) - (*this)); 535 | Point3c BP((*B) - (*this)); 536 | Point3c AB((*A) - (*B)); 537 | 538 | if (AB*AP <= 0) return AP.length(); 539 | if (AB*BP >= 0) return BP.length(); 540 | 541 | return distanceFromLine(A,B); 542 | } 543 | 544 | /////////////////// Distance from a segment /////////////////////// 545 | //// 'cc' is initialized as the point of the segment whose //// 546 | //// distance from 'this' is minimum. //// 547 | 548 | double Point3c::distanceFromEdge(const Point3c *A, const Point3c *B, Point3c *cc) const 549 | { 550 | Point3c AP((*A) - (*this)); 551 | Point3c BP((*B) - (*this)); 552 | Point3c AB((*A) - (*B)); 553 | 554 | if (AB*AP <= 0) { cc->setValue(A); return AP.length(); } 555 | if (AB*BP >= 0) { cc->setValue(B); return BP.length(); } 556 | 557 | return distanceFromLine(A, B, cc); 558 | } 559 | 560 | /////////// Distance of two straight lines /////////////// 561 | 562 | double Point3c::distanceLineLine(const Point3c *A, const Point3c *A1, const Point3c *B1) const 563 | { 564 | Point3c uu1 = ((*this) - (*A))&((*A1) - (*B1)); 565 | coord nom = ((*A) - (*A1))*(uu1); 566 | return sqrt(TMESH_TO_DOUBLE((nom*nom) / uu1.squaredLength())); 567 | } 568 | 569 | ///////////////// Angle between two vectors /////////////// 570 | 571 | double Point3c::getAngle(const Point3c& p) const 572 | { 573 | return atan2(((*this)&p).length(), TMESH_TO_DOUBLE(((*this)*p))); 574 | } 575 | 576 | 577 | 578 | 579 | 580 | 581 | // This can be used with jqsort 582 | int xyzCompare(const void *a, const void *b) 583 | { 584 | if (((((Point3c *)a)->x < ((Point3c *)b)->x))) return -1; 585 | if (((((Point3c *)a)->x >((Point3c *)b)->x))) return 1; 586 | if (((((Point3c *)a)->y < ((Point3c *)b)->y))) return -1; 587 | if (((((Point3c *)a)->y >((Point3c *)b)->y))) return 1; 588 | if (((((Point3c *)a)->z < ((Point3c *)b)->z))) return -1; 589 | if (((((Point3c *)a)->z >((Point3c *)b)->z))) return 1; 590 | 591 | return 0; 592 | } 593 | 594 | } //namespace T_MESH 595 | -------------------------------------------------------------------------------- /src/tmesh.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * tmesh.cpp * 3 | * This file is part of the TMesh_Kernel Library * 4 | * * 5 | * Authors: Marco Attene * 6 | * Copyright(C) 2012: IMATI-GE / CNR * 7 | * IMATI-GE / CNR is Consiglio Nazionale delle Ricerche * 8 | * Istituto di Matematica Applicata e Tecnologie Informatiche * 9 | * Genova (Italy) * 10 | * * 11 | * TMesh_Kernel is free software; you can redistribute it and/or modify * 12 | * it under the terms of the GNU Lesser General Public License as published * 13 | * by the Free Software Foundation; either version 3 of the License, or (at * 14 | * your option) any later version. * 15 | * * 16 | * TMesh_Kernel is distributed in the hope that it will be useful, but * 17 | * WITHOUT ANY WARRANTY; without even the implied warranty of * 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser * 19 | * General Public License for more details. * 20 | * * 21 | * You should have received a copy of the GNU Lesser General Public License * 22 | * along with TMesh_Kernel. If not, see http://www.gnu.org/licenses/. * 23 | * * 24 | ****************************************************************************/ 25 | 26 | #include "tmesh_kernel.h" 27 | #include "expansion.h" 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | namespace T_MESH 34 | { 35 | 36 | void (* TMesh::display_message)(const char*, int) = NULL; 37 | 38 | char *TMesh::app_name = NULL; 39 | char *TMesh::app_version = NULL; 40 | char *TMesh::app_year = NULL; 41 | char *TMesh::app_authors = NULL; 42 | char *TMesh::app_url = NULL; 43 | char *TMesh::app_maillist = NULL; 44 | const char *TMesh::filename = NULL; 45 | bool TMesh::quiet = false; 46 | 47 | thread_initializer tmesh_thread_initializer; 48 | 49 | ///////////// Prints a fatal error message and exits ///////////// 50 | 51 | void TMesh::error(const char *msg, ...) 52 | { 53 | static char fmt[2048], fms[4096]; 54 | va_list ap; 55 | va_start(ap, msg); 56 | strcpy(fmt,"\nERROR- "); 57 | strcat(fmt,msg); 58 | vsprintf(fms,fmt,ap); 59 | 60 | if (display_message != NULL) 61 | display_message(fms, DISPMSG_ACTION_ERRORDIALOG); 62 | else 63 | { 64 | fprintf(stderr,fms); 65 | exit(-1); 66 | } 67 | } 68 | 69 | ///////////// Prints a warning message ///////////// 70 | 71 | void TMesh::warning(const char *msg, ...) 72 | { 73 | if (quiet) return; 74 | static char fmt[2048], fms[4096]; 75 | va_list ap; 76 | va_start(ap, msg); 77 | strcpy(fmt,"WARNING- "); 78 | strcat(fmt,msg); 79 | vsprintf(fms,fmt,ap); 80 | 81 | if (display_message != NULL) 82 | display_message(fms, DISPMSG_ACTION_PUTMESSAGE); 83 | else 84 | fputs(fms, stderr); 85 | 86 | va_end(ap); 87 | } 88 | 89 | ///////////// Prints an information message ///////////// 90 | 91 | void TMesh::info(const char *msg, ...) 92 | { 93 | if (quiet) return; 94 | static char fmt[2048], fms[4096]; 95 | va_list ap; 96 | va_start(ap, msg); 97 | strcpy(fmt,"INFO- "); 98 | strcat(fmt,msg); 99 | vsprintf(fms,fmt,ap); 100 | 101 | if (display_message != NULL) 102 | display_message(fms, DISPMSG_ACTION_PUTMESSAGE); 103 | else 104 | printf(fms); 105 | 106 | va_end(ap); 107 | } 108 | 109 | ///////// Reports progress status for a process ////////// 110 | 111 | void TMesh::begin_progress() 112 | { 113 | if (quiet) return; 114 | if (display_message != NULL) 115 | display_message("\n", DISPMSG_ACTION_PUTNEWLINE); 116 | else 117 | printf("\n"); 118 | } 119 | 120 | void TMesh::report_progress(const char *msg, ...) 121 | { 122 | if (quiet) return; 123 | static char fmt[2048] = "\r"; 124 | static char fms[4096]; 125 | static char rotating_bar[5] = "-\\|/"; 126 | static unsigned char wc=0; 127 | 128 | if (msg == NULL) 129 | { 130 | sprintf(fms,"%c",rotating_bar[wc++]); if (wc==4) wc=0; 131 | strcpy(fmt+1,fms); 132 | 133 | if (display_message != NULL) 134 | display_message(fmt, DISPMSG_ACTION_PUTPROGRESS); 135 | else 136 | { 137 | printf("%s",fmt); 138 | fflush(stdout); 139 | } 140 | } 141 | else 142 | { 143 | va_list ap; 144 | va_start(ap, msg); 145 | strcpy(fmt+1,msg); 146 | vsprintf(fms,fmt,ap); 147 | 148 | if (display_message != NULL) 149 | display_message(fms, DISPMSG_ACTION_PUTPROGRESS); 150 | else 151 | { 152 | printf("%s", fms); 153 | fflush(stdout); 154 | } 155 | va_end(ap); 156 | } 157 | } 158 | 159 | void TMesh::end_progress() 160 | { 161 | if (quiet) return; 162 | if (display_message != NULL) 163 | display_message("\n", DISPMSG_ACTION_PUTNEWLINE); 164 | else 165 | printf("\n"); 166 | } 167 | 168 | void TMesh::useRationals(bool u) 169 | { 170 | #ifdef USE_HYBRID_KERNEL 171 | coord::useRationals(u); 172 | #else 173 | if (u) TMesh::warning("TMesh - Switch to rationals attempted in Fast mode. This has no effect!\n"); 174 | #endif 175 | } 176 | 177 | bool TMesh::isUsingRationals() 178 | { 179 | #ifdef USE_HYBRID_KERNEL 180 | return coord::isUsingRationals(); 181 | #else 182 | return false; 183 | #endif 184 | } 185 | 186 | void TMesh::addMessageToLogFile(const char *msg) 187 | { 188 | FILE *fp = fopen("tmesh.log", "a"); 189 | fprintf(fp, msg); 190 | fclose(fp); 191 | } 192 | 193 | // Get current date/time, format is YYYY-MM-DD.HH:mm:ss 194 | char *currentDateTime() 195 | { 196 | time_t now = time(0); 197 | struct tm tstruct; 198 | static char buf[80]; 199 | tstruct = *localtime(&now); 200 | strftime(buf, sizeof(buf), "%Y-%m-%d.%X", &tstruct); 201 | 202 | return buf; 203 | } 204 | 205 | void TMesh::logToFileAndExit(const char *s) 206 | { 207 | static char msg[2048]; 208 | sprintf(msg, "%s\nFILE: %s\nRETURN VALUE: %s\n\n", currentDateTime(), (filename) ? (filename) : ("unknown"), s); 209 | addMessageToLogFile(msg); 210 | TMesh::error(msg); 211 | } 212 | 213 | void TMesh::exitOnTimeout(clock_t ts) 214 | { 215 | static clock_t beginning_time, timeout_secs; 216 | if (ts != 0) { beginning_time = clock(); timeout_secs = ts; } 217 | else if (((clock() - beginning_time) / 1000) > timeout_secs) logToFileAndExit("Timeout reached"); 218 | } 219 | 220 | void TMesh::printElapsedTime(bool reset) 221 | { 222 | static clock_t beginning_time; 223 | if (reset) beginning_time = clock(); 224 | else printf("\n\n********** PARTIAL ELAPSED: %ld msecs\n\n", (clock() - beginning_time)); 225 | } 226 | 227 | void TMesh::init(void(*dm)(const char *, int)) 228 | { 229 | display_message = dm; 230 | app_name = NULL; 231 | app_version = NULL; 232 | app_year = NULL; 233 | app_authors = NULL; 234 | app_url = NULL; 235 | app_maillist = NULL; 236 | filename = NULL; 237 | quiet = false; 238 | 239 | setFPU53BitsPrecision(); 240 | 241 | #ifdef USE_HYBRID_KERNEL 242 | setFPUModeToRoundUP(); 243 | useRationals(false); 244 | #endif 245 | } 246 | 247 | } //namespace T_MESH 248 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1) 2 | ################################################################################ 3 | 4 | set(test_sources 5 | main.cpp 6 | test_kernel.cpp 7 | ) 8 | 9 | add_executable(unit_tests ${test_sources}) 10 | 11 | foreach(source IN ITEMS ${test_sources}) 12 | source_group("tests" FILES "${source}") 13 | endforeach() 14 | 15 | target_link_libraries(unit_tests PUBLIC TMesh_Kernel catch warnings::all) 16 | 17 | 18 | 19 | if(TMESH_KERNEL_WITH_SANITIZERS) 20 | add_sanitizers(unit_tests) 21 | endif() 22 | 23 | # Register tests 24 | set(PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS ON) 25 | include(Catch) 26 | catch_discover_tests(unit_tests) 27 | -------------------------------------------------------------------------------- /tests/main.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // Keep this file empty, and implement unit tests in separate compilation units! 3 | //////////////////////////////////////////////////////////////////////////////// 4 | 5 | #define CATCH_CONFIG_MAIN 6 | #include 7 | 8 | -------------------------------------------------------------------------------- /tests/test_kernel.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * test_kernel.cpp * 3 | * This file is part of the TMesh_Kernel Library * 4 | * * 5 | * Authors: Marco Attene * 6 | * Copyright(C) 2012: IMATI-GE / CNR * 7 | * IMATI-GE / CNR is Consiglio Nazionale delle Ricerche * 8 | * Istituto di Matematica Applicata e Tecnologie Informatiche * 9 | * Genova (Italy) * 10 | * * 11 | * TMesh_Kernel is free software; you can redistribute it and/or modify * 12 | * it under the terms of the GNU Lesser General Public License as published * 13 | * by the Free Software Foundation; either version 3 of the License, or (at * 14 | * your option) any later version. * 15 | * * 16 | * TMesh_Kernel is distributed in the hope that it will be useful, but * 17 | * WITHOUT ANY WARRANTY; without even the implied warranty of * 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser * 19 | * General Public License for more details. * 20 | * * 21 | * You should have received a copy of the GNU Lesser General Public License * 22 | * along with TMesh_Kernel. If not, see http://www.gnu.org/licenses/. * 23 | * * 24 | ****************************************************************************/ 25 | 26 | #include "tmesh_kernel.h" 27 | #include 28 | #include 29 | #include 30 | 31 | using namespace T_MESH; 32 | 33 | TEST_CASE("operations", "[kernel]") 34 | { 35 | TMesh::init(); // This is mandatory to correctly set up the FPU for exact computation 36 | 37 | // The type 'coord' represents the basic hybrid number in TMesh. 38 | // It can be handled as an IEEE 754 standard double in most cases. 39 | coord q_x = 3.0; 40 | coord q_y = 4.0; 41 | coord q_z = 5.0; 42 | 43 | // for example... 44 | q_x += (q_y - q_z); 45 | 46 | // When necessary, the TMESH_TO_DOUBLE macro approximates a coord to an actual double 47 | double sqrtex = sqrt( TMESH_TO_DOUBLE(q_y) ); 48 | 49 | // And a double can be seamlessly assigned to a coord 50 | q_z = sqrtex; 51 | 52 | // A Point in TMesh is a triplet of coordinates, each having type 'coord' 53 | // The following example shows how to manipulate points as vectors 54 | // Here we calculate the projection of 'p' on the plane by A, B and C 55 | Point q(q_x, q_y, q_z); 56 | Point A(0, 0, 0); 57 | Point B(2, 0, 0); 58 | Point C(0, 2, 0); 59 | 60 | Point BA = B - A; 61 | Point CA = C - A; 62 | Point plane_vec = BA & CA; // Operator '&' represents the cross product 63 | 64 | // The previous three lines can be compacted into a single line as follows: 65 | // Point plane_vec = (B - A) & (C - A); 66 | 67 | // Here we calculate the projection as the intersection of a straight line by 68 | // q and orthogonal to the plane. 69 | Point lifted_q = q + plane_vec; 70 | Point projected_point = Point::linePlaneIntersection(q, lifted_q, A, B, C); 71 | 72 | std::cout << "Projected point coordinates: "; 73 | projected_point.printPoint(); 74 | //TODO add a REQUIRE 75 | 76 | 77 | // By default, TMesh works in floating point mode 78 | 79 | // Declare four coplanar points 80 | Point p1(5, 1, 0); 81 | Point p2(4, 2, 0); 82 | Point p3(8, 1, 1); 83 | Point p4(7, 2, 1); 84 | 85 | // Predicates in TMesh are always exact - the following reports coplanarity as expected 86 | // even if we work with floating point coordinates 87 | if (p1.exactOrientation(p2, p3, p4) == 0) std::cout << "Points pi are coplanar\n"; 88 | else std::cout << "Points pi are not coplanar\n"; 89 | REQUIRE(p1.exactOrientation(p2, p3, p4) == 0); 90 | 91 | // We now create scaled copies of the pi's 92 | Point q1 = p1 / 3; 93 | Point q2 = p2 / 3; 94 | Point q3 = p3 / 3; 95 | Point q4 = p4 / 3; 96 | 97 | // Coordinates in the qi's are not exact scales of those in the pi's because we are 98 | // approximating them using floating point numbers 99 | if (q1.exactOrientation(q2, q3, q4) == 0) std::cout << "Points qi are coplanar\n"; 100 | else std::cout << "Points qi are not coplanar\n"; 101 | REQUIRE(q1.exactOrientation(q2, q3, q4) != 0); 102 | 103 | // Now we switch to rational mode 104 | TMesh::useRationals(); 105 | 106 | // We create other scaled copies of the pi's 107 | Point r1 = p1 / 3; 108 | Point r2 = p2 / 3; 109 | Point r3 = p3 / 3; 110 | Point r4 = p4 / 3; 111 | 112 | // Coordinates in the ri's are exact scales of those in the pi's because we are 113 | // representing them using rational numbers 114 | if (r1.exactOrientation(r2, r3, r4) == 0) std::cout << "Points ri are coplanar\n"; 115 | else std::cout << "Points ri are not coplanar\n"; 116 | REQUIRE(r1.exactOrientation(r2, r3, r4) == 0); 117 | 118 | // Now we switch back to floating point mode 119 | TMesh::useRationals(false); 120 | 121 | // Even if we switched back to floating point, coordinates in the ri's are still 122 | // rational numbers. That is why the following still reports coplanarity. 123 | if (r1.exactOrientation(r2, r3, r4) == 0) std::cout << "Points ri are coplanar\n"; 124 | else std::cout << "Points ri are not coplanar\n"; 125 | REQUIRE(r1.exactOrientation(r2, r3, r4) == 0); 126 | 127 | // The following is just an example of hybrid calculation where q1 has floating 128 | // point coords while the ri's have rational coords. 129 | if (q1.exactOrientation(r2, r3, r4) == 0) std::cout << "Points (q1, r2, r3, r4) are coplanar\n"; 130 | else std::cout << "Points (q1, r2, r3, r4) are not coplanar\n"; 131 | REQUIRE(q1.exactOrientation(r2, r3, r4) != 0); 132 | } 133 | 134 | 135 | TEST_CASE("Multi-threading", "[kernel]") 136 | { 137 | // Multi-threading example 138 | 139 | const int num_tests = 1000; 140 | 141 | // Switch to rational mode to make Points assume exact coordinates. 142 | // We also divide by three to have a high probability that the resulting 143 | // coordinates cannot be represented using floating points. 144 | // In this way, we are stressing TMesh on purpose by making it use 145 | // rationals in most places to calculate a large number of insphere predicates. 146 | TMesh::useRationals(true); 147 | 148 | clock_t c0 = clock(); 149 | for (int i = 0; i < num_tests; i++) 150 | { 151 | Point p1(rand(), rand(), rand()); p1 /= 3; 152 | Point p2(rand(), rand(), rand()); p2 /= 3; 153 | Point p3(rand(), rand(), rand()); p3 /= 3; 154 | Point p4(rand(), rand(), rand()); p4 /= 3; 155 | Point p5(rand(), rand(), rand()); p5 /= 3; 156 | REQUIRE(p1.inSphere(&p2, &p3, &p4, &p5)); 157 | } 158 | 159 | std::cout << "Needed " << ((clock() - c0) / 1000) << " seconds to sequentially calculate " << num_tests << " insphere predicates.\n"; 160 | 161 | // Here we use OpenMP to concurrently redo the same calculation. 162 | // Remember to always use TMESH_OMP_CLAUSES to correctly 163 | // set TMesh_Kernel mode in all the threads. 164 | 165 | c0 = clock(); 166 | 167 | #pragma omp parallel for TMESH_OMP_CLAUSES schedule(dynamic) 168 | for (int i = 0; i < num_tests; i++) 169 | { 170 | Point p1(rand(), rand(), rand()); p1 /= 3; 171 | Point p2(rand(), rand(), rand()); p2 /= 3; 172 | Point p3(rand(), rand(), rand()); p3 /= 3; 173 | Point p4(rand(), rand(), rand()); p4 /= 3; 174 | Point p5(rand(), rand(), rand()); p5 /= 3; 175 | REQUIRE(p1.inSphere(&p2, &p3, &p4, &p5)); 176 | } 177 | 178 | std::cout << "Needed " << ((clock() - c0) / 1000) << " seconds to concurrently calculate " << num_tests << " insphere predicates.\n"; 179 | } 180 | --------------------------------------------------------------------------------