diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml new file mode 100644 index 0000000..c8844d9 --- /dev/null +++ b/.github/workflows/ccpp.yml @@ -0,0 +1,23 @@ +name: C/C++ CI + +on: [push] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Install python moduels + run: sudo apt update && sudo apt install -y libeigen3-dev python3-setuptools && pip3 install pybind11 pytest numpy scipy cython + - name: Compile Bybind + run: export CPATH=/usr/include/eigen3 && cd examples/python && source build.sh + - name: Test Bybind + run: | + cd examples/python + python3 -m pytest -s -v test.py + - name: Run cython + run: | + cd examples/cython + python3 setup.py build_ext --inplace && python3 -m pytest -s -v test.py diff --git a/.gitignore b/.gitignore index acb8847..46759a4 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,10 @@ build*/* *.so public/ +<<<<<<< HEAD +*.exe +======= +>>>>>>> master # Eclispe setting --- do not ignore *.cproject and *.project */**/.settings @@ -91,7 +95,11 @@ DocProject/Help/Html2 DocProject/Help/html # Cmake, make and compiled objects on unix +<<<<<<< HEAD +#*.cmake +======= *.cmake +>>>>>>> master *.c.o */CMakeFiles/* */Makefile @@ -141,6 +149,8 @@ Assets/AssetStoreTools* # Visual Studio cache directory .vs/ +<<<<<<< HEAD +======= # Visual Studio Code cache directory .vscode/* !.vscode/settings.json @@ -152,6 +162,7 @@ Assets/AssetStoreTools* # Local History for Visual Studio Code .history/ +>>>>>>> master # Autogenerated VS/MD/Consulo solution and project files ExportedObj/ .consulo/ @@ -185,3 +196,49 @@ sysinfo.txt # Office ~*.pptx +<<<<<<< HEAD + +#Cython https://github.com/cython/cython/blob/master/.gitignore +*.pyc +*.pyo +__pycache__ +*.o + +.*cache*/ + +*/cython/*.c + +/TEST_TMP/ +/build/ +/cython_build/ +/wheelhouse*/ +!tests/build/ +/dist/ +.gitrev +.coverage +*.patch +*.diff +*.orig +*.prof +*.rej +*.log +*.dep +*.swp +*~ +callgrind.out.* + +.ipynb_checkpoints + +# Jetbrains IDE project files +/.idea +/*.iml + +# Pytest +.cache +.pytest_cache +.mypy_cache +<<<<<<< HEAD +======= +======= +>>>>>>> master +>>>>>>> cmakeWin diff --git a/CMakeLists.txt b/CMakeLists.txt index 591e8be..e025eef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,94 +1,92 @@ -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # -# ##### # # # # -# #### ##### ###### # # # # # # # # -# # # # # # ## # # # # # # -# # # # # ##### # # # # #### # ### # -# # # ##### # # # # # # # # # # # -# # # # # # ## # # # # # # # -# #### # ###### # # ##### ##### # # # -# # -# This file is part of openGJK. # -# # -# openGJK is free software: you can redistribute it and/or modify # -# it under the terms of the GNU General Public License as published by # -# the Free Software Foundation, either version 3 of the License, or # -# any later version. # -# # -# openGJK is distributed in the hope that it will be useful, # -# but WITHOUT ANY WARRANTY; without even the implied warranty of # -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See The # -# GNU General Public License for more details. # -# # -# You should have received a copy of the GNU General Public License # -# along with Foobar. If not, see . # -# # -# openGJK: open-source Gilbert-Johnson-Keerthi algorithm # -# Copyright (C) Mattia Montanari 2018 - 2019 # -# http://iel.eng.ox.ac.uk/?page_id=504 # -# # -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - -cmake_minimum_required(VERSION 3.5) -project(openGJK) - -set(CMAKE_C_STANDARD 11) - -message("[${CMAKE_PROJECT_NAME}] Welcome, please change user options if needed.") - -# APPLY DEFAULT SETTINGS -if(NOT CMAKE_BUILD_TYPE) - message("[${CMAKE_PROJECT_NAME}] Use default CMAKE_BUILD_TYPE") - set(CMAKE_BUILD_TYPE Release) -endif() - - -# PLATFORM-SPECIFIC SETTING -if (UNIX) - find_library(M_LIB m) - set(CMAKE_C_FLAGS "-lm") - set(CMAKE_CXX_FLAGS "-lm") -else () - set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) -endif () - -# COMPILER SETTING -IF(CMAKE_BUILD_TYPE MATCHES Release) - set(CMAKE_BUILD_TYPE Release) -ELSEIF(CMAKE_BUILD_TYPE MATCHES Debug) - set(CMAKE_BUILD_TYPE Debug) -ENDIF() - -if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") - # using GCC - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wextra -finline-functions") - set(CMAKE_CXX_FLAGS_DEBUG "-g -DDEBUG") - set(CMAKE_CXX_FLAGS_RELEASE "-O3") - - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wextra -finline-functions") - set(CMAKE_C_FLAGS_DEBUG "-g -DDEBUG") - set(CMAKE_C_FLAGS_RELEASE "-O3") - - add_compile_options(-static-libgcc -static-libstdc++ ) - add_definitions(-DMT) -elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") - # using Visual Studio C++ - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4131 /wd4701 /wd4255 /wd4710 /wd4820 /wd4711 /wd5045") - set(CMAKE_CXX_FLAGS_DEBUG "-DDEBUG /D_DEBUG /MDd /Zi /Ob0 /Od /RTC1") - set(CMAKE_CXX_FLAGS_RELEASE "/Ox") - - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4131 /wd4701 /wd4255 /wd4710 /wd4820 /wd4711 /wd5045") - set(CMAKE_C_FLAGS_DEBUG "-DDEBUG /D_DEBUG /MDd /Zi /Ob0 /Od /RTC1") - set(CMAKE_C_FLAGS_RELEASE "/Ox") - - set(CMAKE_SUPPRESS_REGENERATION true) - - endif() - -# DEBUG FLAGS -IF(CMAKE_BUILD_TYPE MATCHES Debug) - add_definitions(-DDEBUG) -ENDIF() - -# INCLUDE LIBRARY AND EXAMPLE DIR -add_subdirectory(lib) -add_subdirectory(example1_c) +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # +# ##### # # # # +# #### ##### ###### # # # # # # # # +# # # # # # ## # # # # # # +# # # # # ##### # # # # #### # ### # +# # # ##### # # # # # # # # # # # +# # # # # # ## # # # # # # # +# #### # ###### # # ##### ##### # # # +# # +# This file is part of openGJK. # +# # +# OpenGJK is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# any later version. # +# # +# OpenGJK is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See The # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with OpenGJK. If not, see . # +# # +# openGJK: open-source Gilbert-Johnson-Keerthi algorithm # +# Copyright (C) Mattia Montanari 2018 - 2020 # +# http://iel.eng.ox.ac.uk/?page_id=504 # +# # +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # + +cmake_minimum_required(VERSION 3.13) + +set(CMAKE_POLICY_DEFAULT_CMP0079 NEW) +set(LIBRARY_VERSION "2.0.3") + +project(openGJKlib VERSION ${LIBRARY_VERSION} LANGUAGES C) + +set(CMAKE_C_STANDARD 11) + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") +include(CMakeDefaults) +include(CompilerFlags) +include(PlatformDefaults) + +message( "[${PROJECT_NAME}] CMake setting ..") +message(STATUS "Version : " ${CMAKE_PROJECT_VERSION} ) +message(STATUS "Build type : " ${CMAKE_BUILD_TYPE} ) + +# Specify project specific and user custum options +include(CMakeProjectOptions) + +set( SOURCE_FILES src/openGJK.c ) +set( SOURCE_HEADS include/openGJK/openGJK.h) + +IF(BUILD_STATIC_LIB) + add_library(${PROJECT_NAME} STATIC ${SOURCE_FILES} ${SOURCE_HEADS}) + add_definitions(-DCMAKE_WINDOWS_EXPORT_ALL_SYMBOLS=TRUE -DBUILD_SHARED_LIBS=FALSE) +ELSE() + add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES} ${SOURCE_HEADS}) + add_definitions(-DCMAKE_WINDOWS_EXPORT_ALL_SYMBOLS=TRUE -DBUILD_SHARED_LIBS=TRUE) +ENDIF(BUILD_STATIC_LIB) + +set_target_properties(${PROJECT_NAME} PROPERTIES PUBLIC_HEADER ${SOURCE_HEADS}) + +# Add compiler flags +include(CompilerFlags) + +# Install setup +install(TARGETS ${PROJECT_NAME} PERMISSIONS WORLD_WRITE ) + +find_package(OpenMP REQUIRED) +if (OPENMP_FOUND) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") + set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}") +endif() + +# Link include file +target_include_directories( ${PROJECT_NAME} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include") + +target_link_libraries(${PROJECT_NAME} ${CMOCKA_LIBRARY} ) + +set(DESTDIR "/usr") +INSTALL(TARGETS ${PROJECT_NAME} + LIBRARY DESTINATION "${DESTDIR}/lib" + PUBLIC_HEADER DESTINATION "${DESTDIR}/include" +) + +if (WITH_EXAMPLES) + add_subdirectory(examples/c) +endif (WITH_EXAMPLES) + +message(STATUS "Completed CMake setting for ${PROJECT_NAME}" ) \ No newline at end of file diff --git a/COPYING b/COPYING index 94a9ed0..818433e 100644 --- a/COPYING +++ b/COPYING @@ -1,674 +1,674 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/INSTALL.md b/INSTALL.md new file mode 100644 index 0000000..8bf2815 --- /dev/null +++ b/INSTALL.md @@ -0,0 +1,151 @@ +# How to compile openGJK + +Using openGJK is very simple. This guide will help you getting started compiling and using openGJK. + +## Requirements + +### Common requirements + +1. A C compiler +2. [CMake](http://www.cmake.org) version 3.5 or above + +## Building +First, you need to configure the compilation, using CMake. + +1. Go inside the `build` dir. Create it if it doesn't exist. +2. Move into `build` dir and use `cmake ..`. On Windows you can specify `cmake -G "Visual Studio 15 2017 Win64" ..`, on Unix `cmake -G "Unix Makefiles" ..`. + +### CMake standard options + +- CMAKE_BUILD_TYPE: The type of build (can be Debug or Release) +- CMAKE_C_COMPILER: The path to the C compiler + +### CMake options defined for openGJK + +Options are defined in the following files: + +- CmakeOptions.cmake + +They can be changed with the -D option: + +`cmake -DVERSION_ACCURATE=ON ..` + +In addition to passing options on the command line, you can browse and edit +CMake options using `cmakesetup` (Windows), `cmake-gui` or `ccmake` (GNU/Linux +and MacOS X). + +- Go to the build dir +- On Windows: run `cmakesetup` +- On GNU/Linux and MacOS X: run `ccmake ..` + +### Install and run + +If all above building commands were executed from `build`, the openGJK library can be found in the `build/src` directory. +You can run the binaries in `build/examples/*`. + +To install the library copy the header file openGJK.h and the binaries in a folder accessible in the search path by all users (on Unix this would normally be /usr/local). + +## Testing + + TO REWRITE!! + +As mention above you can turn on the unit tests and make it possible to easily +execute them: + +`cmake -DCMAKE_BUILD_TYPE=Debug -DUNIT_TESTING=ON ..` + +After that you can simply call `make test` in the build directory or if you +want more output simply call `ctest -V`. + +If you want to enable the generation of coverage files you can do this by +using the following options: + +`cmake -DCMAKE_BUILD_TYPE=Profiling -DUNIT_TESTING=ON ..` + +After building it you will see that you have several coverage options in + +`make help` + +You should have `make ExperimentalCoverage` and running it will create +coverage files. The result is stored in Testing directory. + +## Examples + + +This section presents three examples on how to use openGJK with C, C# and Matlab. + +### C +This example illustrates how to include openGJK in an existing C + program. + +All files for the example are in the `example1_c` folder. The executable built with + CMake reads the coordinates of two polytopes from the input files, + respectively userP.dat and userQ.dat, and computes the minimum distance + between them. + +Notice that the input files must be in the folder from which the executable + is launched, otherwise an error is returned. + +You can edit the coordinates in the input file to test different + polytopes; just remember to edit also the first number in the files + that corresponds to the numbers of vertices that the program will read. + +### Matlab +This example illustrates how to invoke openGJK as a regular built-in + Matlab function. You will need to build mex files (find out the requisites from [Mathworks documentation](https://uk.mathworks.com/help/matlab/matlab_external/what-you-need-to-build-mex-files.html)). + + +Open Matlab and cd into the `example2_mex` folder. By running the + script `runme.m`, Matlab will first compile a mex file (telling you + about the name of the mex file generated) and will call the script + `main.m`. This invokes openGJK within Matlab and illustrates the + result. + +The mex file may be copied and called from any other Matlab project. + +### C# # +This example illustrates how to invoke openGJK in an applications written in C#. You will need [mono](http://www.mono-project.com/) and Microsoft Visual Studio toolchain for C# on Windows. + +The only file required is in the `example3_csharp` folder. This can be compiled in Unix + with mono, or in Windows using Visual Studio. Notice that, however, the openGJK library + is compiled for a specific architecture (usually x64), and this breaks the portability + of the .NET application compiled in this example. + +Below are the steps for compiling the C# application on Windows and Linux. Both + procedures assume the dynamic library of openGJK has been already compiled. + +#### Compile on Windows + 1. Move into the folder `example3_csharp` and create a new folder `example3`. + 2. Copy into this folder the openGJK library or make it available in any directory. + 3. Open Visual Studio and create a new project. As project type select **Console App (.NET Framework)**. + 4. Add to this project the `main.cs` file + 5. Set x64 as the target platform, compile the application and run it. + + +#### Compile on Linux + 1. Move into the folder `example3_csharp` and create a new folder `example3`. + 2. Copy into this folder the openGJK library or install is so that is available in any directory. + 3. Move into that new folder and open a terminal. + 4. Type `mcs -out:example3demo -d:UNIX ../main.cs` + 5. Run the example by typing `mono example3demo` + +## API user reference + +```double gjk( struct bodyA, struct bodyB, struct simplex)``` + +### Documentation +The folder `doc` contains a Doxygen file for generating the documentation of the whole + library. To build the documentation cd into `doc` and call Doxygen from the command line simply by typing `doxygen`. If correctly installed, Doxygen will create html documentation with graphs illustrating the call stack of the functions of the library. + +### Parameters +* **bodyA** The first body. +* **bodyB** The second body. +* **simplex** The simplex used the GJK algorithm at the first iteration. + +### Returns +* **double** the minimum distance between bodyA and bodyB. + +### Description +The function `gjk` computes the minimum Euclidean distance between two bodies using the + GJK algorithm. Note that the simplex used at the first iteration may be initialised by the user, but this is not necessary. + \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..818433e --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/README.md b/README.md index d7b50d3..cc40ddb 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,13 @@ Hello! -======= -I'll never have enough time for this project, but contributes are welcome! Please check out [docs and more details here](https://www.mattiamontanari.com/opengjk/). +This is a simple and reliable C implementation of the Gilbert-Johnson-Keerthi (GJK) algorithm, [docs and details are available here](https://www.mattiamontanari.com/opengjk/). -The best code is in dev branch - Enjoy! +All contributes are all welcome. For instance you could add: + - Support for other shapes: quadrics and splines (easy) + - More python examples and test (easy) + - EPA algorithm (hard) > openGJK, Copyright (c) 2018-2021 > -> Department of Engineering Science. University of Oxford, UK. +> Department of Engineering Science. University of Oxford, UK. \ No newline at end of file diff --git a/lib/CMakeLists.txt b/cmake/CMakeDefaults.cmake similarity index 61% rename from lib/CMakeLists.txt rename to cmake/CMakeDefaults.cmake index 7748490..f69fe89 100644 --- a/lib/CMakeLists.txt +++ b/cmake/CMakeDefaults.cmake @@ -28,53 +28,24 @@ # # # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # +# Include srcdir and builddir in include path to save typing ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY} in every subdir +set(CMAKE_INCLUDE_CURRENT_DIR ON) -project (openGJKlib) +# Put the include dirs which are in the source or build tree +# before all other include dirs, so the headers in the sources +# are prefered over the already installed ones +# since cmake 2.4.1 +set(CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE ON) -set(CMAKE_C_STANDARD 11) +# Use colored output +set(CMAKE_COLOR_MAKEFILE ON) -# SELECT USER OPTIONS -option(VERSION_ACCURATE "Reduce speed to maximise accuracy (OFF)" OFF ) +# Create the compile command database for clang by default +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) -# APPLY USER OPTIONS -IF(VERSION_ACCURATE) - set(USE_PREDICATES ON) - set(openGJK_VERSION "Accurate") -ELSE() - set(USE_PREDICATES OFF) - set(openGJK_VERSION "Fast") -ENDIF() +# Always build with -fPIC +set(CMAKE_POSITION_INDEPENDENT_CODE ON) -# COMPILE -message( "[${CMAKE_PROJECT_NAME}] Compiling ..") -message(STATUS "Version (Accurate,Fast): " ${openGJK_VERSION} ) -message(STATUS "Build type (Debug,Release): " ${CMAKE_BUILD_TYPE} ) - -# Select source files -set( SOURCE_FILES src/openGJK.c ) -set( SOURCE_HEADS include/openGJK/openGJK.h) - -IF(USE_PREDICATES) - # for adpative floating-point artim. - set( SOURCE_FILES ${SOURCE_FILES} ext/predicates.c) - set( SOURCE_HEADS ${SOURCE_HEADS} ext/predicates.h) - # Add flag for adpative floating-point artim. - add_definitions(-DADAPTIVEFP) -ENDIF() - -# Create the (dynamic) library -add_library(${PROJECT_NAME} STATIC ${SOURCE_FILES} ${SOURCE_HEADS}) -add_definitions(-DCMAKE_WINDOWS_EXPORT_ALL_SYMBOLS=TRUE -DBUILD_SHARED_LIBS=FALSE) - -# Link include file -target_include_directories( ${PROJECT_NAME} PUBLIC ${PROJECT_SOURCE_DIR}/include) - -IF(USE_PREDICATES) - # for adpative floating-point artim. - target_include_directories( ${PROJECT_NAME} - PUBLIC ${PROJECT_SOURCE_DIR}/ext - ) -ENDIF() - -# Report -message( ".. DONE!") +# Avoid source tree pollution +set(CMAKE_DISABLE_SOURCE_CHANGES ON) +set(CMAKE_DISABLE_IN_SOURCE_BUILD ON) \ No newline at end of file diff --git a/example1_c/CMakeLists.txt b/cmake/CMakeProjectOptions.cmake similarity index 79% rename from example1_c/CMakeLists.txt rename to cmake/CMakeProjectOptions.cmake index b9c3497..27fd9c5 100644 --- a/example1_c/CMakeLists.txt +++ b/cmake/CMakeProjectOptions.cmake @@ -14,7 +14,7 @@ # the Free Software Foundation, either version 3 of the License, or # # any later version. # # # -# openGJK is distributed in the hope that it will be useful, # +# openGJK is distributed in the hope that it will be useful, # # but WITHOUT ANY WARRANTY; without even the implied warranty of # # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See The # # GNU General Public License for more details. # @@ -23,23 +23,22 @@ # along with Foobar. If not, see . # # # # openGJK: open-source Gilbert-Johnson-Keerthi algorithm # -# Copyright (C) Mattia Montanari 2018 - 2019 # +# Copyright (C) Mattia Montanari 2018 - 2020 # # http://iel.eng.ox.ac.uk/?page_id=504 # # # # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # -project(openGJKdemo) +option(WITH_STATIC_LIB "Build static lib" OFF) +option(WITH_EXAMPLES "Build C example" ON) -message( "[${CMAKE_PROJECT_NAME}] Compiling the executable ..") +# Default build type +set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Release") -# Set source file -set(SOURCE_FILES main.c ) +# APPLY USER OPTIONS +IF (WITH_STATIC_LIB) + set(BUILD_STATIC_LIB ON) +ENDIF (WITH_STATIC_LIB) -# Create the executable -add_executable(demo ${SOURCE_FILES}) - -# Link to openGJK -target_link_libraries(demo openGJKlib ) - -# Report -message( ".. executable DONE!") \ No newline at end of file +# FEEDBACK +message(STATUS " Build static lib (ON): " ${WITH_STATIC_LIB}) +message(STATUS " Build C examples (ON): " ${WITH_EXAMPLES}) \ No newline at end of file diff --git a/cmake/COPYING-CMAKE-SCRIPTS b/cmake/COPYING-CMAKE-SCRIPTS new file mode 100644 index 0000000..4b41776 --- /dev/null +++ b/cmake/COPYING-CMAKE-SCRIPTS @@ -0,0 +1,22 @@ +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/cmake/CompilerChecks.cmake b/cmake/CompilerChecks.cmake new file mode 100644 index 0000000..b326807 --- /dev/null +++ b/cmake/CompilerChecks.cmake @@ -0,0 +1,109 @@ +include(AddCCompilerFlag) +include(CheckCCompilerFlagSSP) + +if (UNIX) + # + # Check for -Werror turned on if possible + # + # This will prevent that compiler flags are detected incorrectly. + # + check_c_compiler_flag("-Werror" REQUIRED_FLAGS_WERROR) + if (REQUIRED_FLAGS_WERROR) + set(CMAKE_REQUIRED_FLAGS "-Werror") + + if (PICKY_DEVELOPER) + list(APPEND SUPPORTED_COMPILER_FLAGS "-Werror") + endif() + endif() + + add_c_compiler_flag("-std=gnu99" SUPPORTED_COMPILER_FLAGS) + add_c_compiler_flag("-Wpedantic" SUPPORTED_COMPILER_FLAGS) + add_c_compiler_flag("-Wall" SUPPORTED_COMPILER_FLAGS) + add_c_compiler_flag("-Wshadow" SUPPORTED_COMPILER_FLAGS) + add_c_compiler_flag("-Wmissing-prototypes" SUPPORTED_COMPILER_FLAGS) + add_c_compiler_flag("-Wcast-align" SUPPORTED_COMPILER_FLAGS) + #add_c_compiler_flag("-Wcast-qual" SUPPORTED_COMPILER_FLAGS) + add_c_compiler_flag("-Werror=address" SUPPORTED_COMPILER_FLAGS) + add_c_compiler_flag("-Wstrict-prototypes" SUPPORTED_COMPILER_FLAGS) + add_c_compiler_flag("-Werror=strict-prototypes" SUPPORTED_COMPILER_FLAGS) + add_c_compiler_flag("-Wwrite-strings" SUPPORTED_COMPILER_FLAGS) + add_c_compiler_flag("-Werror=write-strings" SUPPORTED_COMPILER_FLAGS) + add_c_compiler_flag("-Werror-implicit-function-declaration" SUPPORTED_COMPILER_FLAGS) + add_c_compiler_flag("-Wpointer-arith" SUPPORTED_COMPILER_FLAGS) + add_c_compiler_flag("-Werror=pointer-arith" SUPPORTED_COMPILER_FLAGS) + add_c_compiler_flag("-Wdeclaration-after-statement" SUPPORTED_COMPILER_FLAGS) + add_c_compiler_flag("-Werror=declaration-after-statement" SUPPORTED_COMPILER_FLAGS) + add_c_compiler_flag("-Wreturn-type" SUPPORTED_COMPILER_FLAGS) + add_c_compiler_flag("-Werror=return-type" SUPPORTED_COMPILER_FLAGS) + add_c_compiler_flag("-Wuninitialized" SUPPORTED_COMPILER_FLAGS) + add_c_compiler_flag("-Werror=uninitialized" SUPPORTED_COMPILER_FLAGS) + add_c_compiler_flag("-Wimplicit-fallthrough" SUPPORTED_COMPILER_FLAGS) + add_c_compiler_flag("-Werror=strict-overflow" SUPPORTED_COMPILER_FLAGS) + add_c_compiler_flag("-Wstrict-overflow=2" SUPPORTED_COMPILER_FLAGS) + add_c_compiler_flag("-Wno-format-zero-length" SUPPORTED_COMPILER_FLAGS) + add_c_compiler_flag("-Wmissing-field-initializers" SUPPORTED_COMPILER_FLAGS) + + check_c_compiler_flag("-Wformat" REQUIRED_FLAGS_WFORMAT) + if (REQUIRED_FLAGS_WFORMAT) + list(APPEND SUPPORTED_COMPILER_FLAGS "-Wformat") + set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -Wformat") + endif() + add_c_compiler_flag("-Wformat-security" SUPPORTED_COMPILER_FLAGS) + add_c_compiler_flag("-Werror=format-security" SUPPORTED_COMPILER_FLAGS) + + # Allow zero for a variadic macro argument + string(TOLOWER "${CMAKE_C_COMPILER_ID}" _C_COMPILER_ID) + if ("${_C_COMPILER_ID}" STREQUAL "clang") + add_c_compiler_flag("-Wno-gnu-zero-variadic-macro-arguments" SUPPORTED_COMPILER_FLAGS) + endif() + + add_c_compiler_flag("-fno-common" SUPPORTED_COMPILER_FLAGS) + + if (CMAKE_BUILD_TYPE) + string(TOLOWER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE_LOWER) + if (CMAKE_BUILD_TYPE_LOWER MATCHES (release|relwithdebinfo|minsizerel)) + add_c_compiler_flag("-Wp,-D_FORTIFY_SOURCE=2" SUPPORTED_COMPILER_FLAGS) + endif() + endif() + + check_c_compiler_flag_ssp("-fstack-protector-strong" WITH_STACK_PROTECTOR_STRONG) + if (WITH_STACK_PROTECTOR_STRONG) + list(APPEND SUPPORTED_COMPILER_FLAGS "-fstack-protector-strong") + # This is needed as Solaris has a seperate libssp + if (SOLARIS) + list(APPEND SUPPORTED_LINKER_FLAGS "-fstack-protector-strong") + endif() + else (WITH_STACK_PROTECTOR_STRONG) + check_c_compiler_flag_ssp("-fstack-protector" WITH_STACK_PROTECTOR) + if (WITH_STACK_PROTECTOR) + list(APPEND SUPPORTED_COMPILER_FLAGS "-fstack-protector") + # This is needed as Solaris has a seperate libssp + if (SOLARIS) + list(APPEND SUPPORTED_LINKER_FLAGS "-fstack-protector") + endif() + endif() + endif (WITH_STACK_PROTECTOR_STRONG) + + check_c_compiler_flag_ssp("-fstack-clash-protection" WITH_STACK_CLASH_PROTECTION) + if (WITH_STACK_CLASH_PROTECTION) + list(APPEND SUPPORTED_COMPILER_FLAGS "-fstack-clash-protection") + endif() + + if (PICKY_DEVELOPER) + add_c_compiler_flag("-Wno-error=deprecated-declarations" SUPPORTED_COMPILER_FLAGS) + add_c_compiler_flag("-Wno-error=tautological-compare" SUPPORTED_COMPILER_FLAGS) + endif() + + # Unset CMAKE_REQUIRED_FLAGS + unset(CMAKE_REQUIRED_FLAGS) +endif() + +if (MSVC) + add_c_compiler_flag("/D _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1" SUPPORTED_COMPILER_FLAGS) + add_c_compiler_flag("/D _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT=1" SUPPORTED_COMPILER_FLAGS) + add_c_compiler_flag("/D _CRT_NONSTDC_NO_WARNINGS=1" SUPPORTED_COMPILER_FLAGS) + add_c_compiler_flag("/D _CRT_SECURE_NO_WARNINGS=1" SUPPORTED_COMPILER_FLAGS) +endif() + +set(DEFAULT_C_COMPILE_FLAGS ${SUPPORTED_COMPILER_FLAGS} CACHE INTERNAL "Default C Compiler Flags" FORCE) +set(DEFAULT_LINK_FLAGS ${SUPPORTED_LINKER_FLAGS} CACHE INTERNAL "Default C Linker Flags" FORCE) diff --git a/cmake/CompilerFlags.cmake b/cmake/CompilerFlags.cmake new file mode 100644 index 0000000..29cf75b --- /dev/null +++ b/cmake/CompilerFlags.cmake @@ -0,0 +1,103 @@ +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # +# ##### # # # # +# #### ##### ###### # # # # # # # # +# # # # # # ## # # # # # # +# # # # # ##### # # # # #### # ### # +# # # ##### # # # # # # # # # # # +# # # # # # ## # # # # # # # +# #### # ###### # # ##### ##### # # # +# # +# This file is part of openGJK. # +# # +# openGJK is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# any later version. # +# # +# openGJK is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See The # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with openGJK. If not, see . # +# # +# openGJK: open-source Gilbert-Johnson-Keerthi algorithm # +# Copyright (C) Mattia Montanari 2018 - 2019 # +# http://iel.eng.ox.ac.uk/?page_id=504 # +# # +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # + + +# PLATFORM-SPECIFIC SETTING +if (UNIX) + find_library(M_LIB m) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -lm") +else () + set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) +endif () + +if ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU") + # using GCC + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wextra -Werror") + + add_compile_options(-static-libgcc -static-libstdc++ ) + add_definitions(-DMT) + +elseif ("${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC") + + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4131 /wd4701 /wd4255 /wd4710 /wd4820 /wd4711 /wd5045") + set(CMAKE_C_FLAGS_DEBUG "-DDEBUG /D_DEBUG /MDd /Zi /Ob0 /Od /RTC1") + set(CMAKE_C_FLAGS_RELEASE "/Ox") + + set(CMAKE_SUPPRESS_REGENERATION true) + +endif() + +if (UNIX AND NOT WIN32) + + # Activate with: -DCMAKE_BUILD_TYPE=Debug + set(CMAKE_C_FLAGS_DEBUG "-g -DDEBUG -Wall -Wextra -Werror" + CACHE STRING "Flags used by the C compiler during DEBUG builds.") + + # Activate with: -DCMAKE_BUILD_TYPE=Release + set(CMAKE_C_FLAGS_RELEASE "-O3 -Wall -finline-functions -Wextra -Werror" + CACHE STRING "Flags used by the C compiler during RELEASE builds.") + + # Activate with: -DCMAKE_BUILD_TYPE=Profiling + set(CMAKE_C_FLAGS_PROFILING "-O0 -g -fprofile-arcs -ftest-coverage" + CACHE STRING "Flags used by the C compiler during PROFILING builds.") + set(CMAKE_CXX_FLAGS_PROFILING "-O0 -g -fprofile-arcs -ftest-coverage" + CACHE STRING "Flags used by the CXX compiler during PROFILING builds.") + set(CMAKE_SHARED_LINKER_FLAGS_PROFILING "-fprofile-arcs -ftest-coverage" + CACHE STRING "Flags used by the linker during the creation of shared libraries during PROFILING builds.") + set(CMAKE_MODULE_LINKER_FLAGS_PROFILING "-fprofile-arcs -ftest-coverage" + CACHE STRING "Flags used by the linker during the creation of shared libraries during PROFILING builds.") + set(CMAKE_EXEC_LINKER_FLAGS_PROFILING "-fprofile-arcs -ftest-coverage" + CACHE STRING "Flags used by the linker during PROFILING builds.") + + # Activate with: -DCMAKE_BUILD_TYPE=AddressSanitizer + set(CMAKE_C_FLAGS_ADDRESSSANITIZER "-g -O1 -fsanitize=address -fno-omit-frame-pointer" + CACHE STRING "Flags used by the C compiler during ADDRESSSANITIZER builds.") + set(CMAKE_CXX_FLAGS_ADDRESSSANITIZER "-g -O1 -fsanitize=address -fno-omit-frame-pointer" + CACHE STRING "Flags used by the CXX compiler during ADDRESSSANITIZER builds.") + set(CMAKE_SHARED_LINKER_FLAGS_ADDRESSSANITIZER "-fsanitize=address" + CACHE STRING "Flags used by the linker during the creation of shared libraries during ADDRESSSANITIZER builds.") + set(CMAKE_MODULE_LINKER_FLAGS_ADDRESSSANITIZER "-fsanitize=address" + CACHE STRING "Flags used by the linker during the creation of shared libraries during ADDRESSSANITIZER builds.") + set(CMAKE_EXEC_LINKER_FLAGS_ADDRESSSANITIZER "-fsanitize=address" + CACHE STRING "Flags used by the linker during ADDRESSSANITIZER builds.") + + # Activate with: -DCMAKE_BUILD_TYPE=MemorySanitizer + set(CMAKE_C_FLAGS_MEMORYSANITIZER "-g -O2 -fsanitize=memory -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer" + CACHE STRING "Flags used by the C compiler during MEMORYSANITIZER builds.") + set(CMAKE_CXX_FLAGS_MEMORYSANITIZER "-g -O2 -fsanitize=memory -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer" + CACHE STRING "Flags used by the CXX compiler during MEMORYSANITIZER builds.") + set(CMAKE_SHARED_LINKER_FLAGS_MEMORYSANITIZER "-fsanitize=memory" + CACHE STRING "Flags used by the linker during the creation of shared libraries during MEMORYSANITIZER builds.") + set(CMAKE_MODULE_LINKER_FLAGS_MEMORYSANITIZER "-fsanitize=memory" + CACHE STRING "Flags used by the linker during the creation of shared libraries during MEMORYSANITIZER builds.") + set(CMAKE_EXEC_LINKER_FLAGS_MEMORYSANITIZER "-fsanitize=memory" + CACHE STRING "Flags used by the linker during MEMORYSANITIZER builds.") + +endif() diff --git a/cmake/ConfigureChecks.cmake b/cmake/ConfigureChecks.cmake new file mode 100644 index 0000000..fe8da35 --- /dev/null +++ b/cmake/ConfigureChecks.cmake @@ -0,0 +1,149 @@ +include(CheckIncludeFile) +include(CheckSymbolExists) +include(CheckFunctionExists) +include(CheckLibraryExists) +include(CheckTypeSize) +include(CheckCXXSourceCompiles) +include(CheckStructHasMember) +include(TestBigEndian) + +set(PACKAGE ${PROJECT_NAME}) +set(VERSION ${PROJECT_VERSION}) +set(DATADIR ${DATA_INSTALL_DIR}) +set(LIBDIR ${CMAKE_INSTALL_LIBDIR}) +set(PLUGINDIR "${PLUGIN_INSTALL_DIR}-${LIBRARY_SOVERSION}") +set(SYSCONFDIR ${SYSCONF_INSTALL_DIR}) + +set(BINARYDIR ${CMAKE_BINARY_DIR}) +set(SOURCEDIR ${CMAKE_SOURCE_DIR}) + +function(COMPILER_DUMPVERSION _OUTPUT_VERSION) + # Remove whitespaces from the argument. + # This is needed for CC="ccache gcc" cmake .. + string(REPLACE " " "" _C_COMPILER_ARG "${CMAKE_C_COMPILER_ARG1}") + + execute_process( + COMMAND + ${CMAKE_C_COMPILER} ${_C_COMPILER_ARG} -dumpversion + OUTPUT_VARIABLE _COMPILER_VERSION + ) + + string(REGEX REPLACE "([0-9])\\.([0-9])(\\.[0-9])?" "\\1\\2" + _COMPILER_VERSION ${_COMPILER_VERSION}) + + set(${_OUTPUT_VERSION} ${_COMPILER_VERSION} PARENT_SCOPE) +endfunction() + +if(CMAKE_COMPILER_IS_GNUCC AND NOT MINGW) + compiler_dumpversion(GNUCC_VERSION) + if (NOT GNUCC_VERSION EQUAL 34) + check_c_compiler_flag("-fvisibility=hidden" WITH_VISIBILITY_HIDDEN) + endif (NOT GNUCC_VERSION EQUAL 34) +endif(CMAKE_COMPILER_IS_GNUCC AND NOT MINGW) + +# DEFINITIONS +if (SOLARIS) + add_definitions(-D__EXTENSIONS__) +endif (SOLARIS) + +# HEADER FILES +check_include_file(assert.h HAVE_ASSERT_H) +check_include_file(inttypes.h HAVE_INTTYPES_H) +check_include_file(io.h HAVE_IO_H) +check_include_file(malloc.h HAVE_MALLOC_H) +check_include_file(memory.h HAVE_MEMORY_H) +check_include_file(setjmp.h HAVE_SETJMP_H) +check_include_file(signal.h HAVE_SIGNAL_H) +check_include_file(stdarg.h HAVE_STDARG_H) +check_include_file(stddef.h HAVE_STDDEF_H) +check_include_file(stdint.h HAVE_STDINT_H) +check_include_file(stdio.h HAVE_STDIO_H) +check_include_file(stdlib.h HAVE_STDLIB_H) +check_include_file(string.h HAVE_STRING_H) +check_include_file(strings.h HAVE_STRINGS_H) +check_include_file(sys/stat.h HAVE_SYS_STAT_H) +check_include_file(sys/types.h HAVE_SYS_TYPES_H) +check_include_file(time.h HAVE_TIME_H) +check_include_file(unistd.h HAVE_UNISTD_H) + +if (HAVE_TIME_H) + check_struct_has_member("struct timespec" tv_sec "time.h" HAVE_STRUCT_TIMESPEC) +endif (HAVE_TIME_H) + +# FUNCTIONS +check_function_exists(calloc HAVE_CALLOC) +check_function_exists(exit HAVE_EXIT) +check_function_exists(fprintf HAVE_FPRINTF) +check_function_exists(free HAVE_FREE) +check_function_exists(longjmp HAVE_LONGJMP) +check_function_exists(siglongjmp HAVE_SIGLONGJMP) +check_function_exists(malloc HAVE_MALLOC) +check_function_exists(memcpy HAVE_MEMCPY) +check_function_exists(memset HAVE_MEMSET) +check_function_exists(printf HAVE_PRINTF) +check_function_exists(setjmp HAVE_SETJMP) +check_function_exists(signal HAVE_SIGNAL) +check_function_exists(strsignal HAVE_STRSIGNAL) +check_function_exists(strcmp HAVE_STRCMP) +check_function_exists(clock_gettime HAVE_CLOCK_GETTIME) + +if (WIN32) + check_function_exists(_vsnprintf_s HAVE__VSNPRINTF_S) + check_function_exists(_vsnprintf HAVE__VSNPRINTF) + check_function_exists(_snprintf HAVE__SNPRINTF) + check_function_exists(_snprintf_s HAVE__SNPRINTF_S) + check_symbol_exists(snprintf stdio.h HAVE_SNPRINTF) + check_symbol_exists(vsnprintf stdio.h HAVE_VSNPRINTF) +else (WIN32) + check_function_exists(sprintf HAVE_SNPRINTF) + check_function_exists(vsnprintf HAVE_VSNPRINTF) +endif (WIN32) + +find_library(RT_LIBRARY rt) +if (RT_LIBRARY AND NOT LINUX AND NOT ANDROID) + set(CMOCKA_REQUIRED_LIBRARIES ${RT_LIBRARY} CACHE INTERNAL "cmocka required system libraries") +endif () + +# OPTIONS +check_c_source_compiles(" +__thread int tls; + +int main(void) { + return 0; +}" HAVE_GCC_THREAD_LOCAL_STORAGE) + +if (WIN32) +check_c_source_compiles(" +__declspec(thread) int tls; + +int main(void) { + return 0; +}" HAVE_MSVC_THREAD_LOCAL_STORAGE) +endif(WIN32) + +if (HAVE_TIME_H AND HAVE_STRUCT_TIMESPEC AND HAVE_CLOCK_GETTIME) + if (RT_LIBRARY) + set(CMAKE_REQUIRED_LIBRARIES ${RT_LIBRARY}) + endif() + + check_c_source_compiles(" +#include + +int main(void) { + struct timespec ts; + + clock_gettime(CLOCK_REALTIME, &ts); + + return 0; +}" HAVE_CLOCK_REALTIME) + + # reset cmake requirements + set(CMAKE_REQUIRED_INCLUDES) + set(CMAKE_REQUIRED_LIBRARIES) +endif () + +# ENDIAN +if (NOT WIN32) + set(WORDS_SIZEOF_VOID_P ${CMAKE_SIZEOF_VOID_P}) + test_big_endian(WORDS_BIGENDIAN) +endif (NOT WIN32) diff --git a/cmake/PlatformDefaults.cmake b/cmake/PlatformDefaults.cmake new file mode 100644 index 0000000..46c3185 --- /dev/null +++ b/cmake/PlatformDefaults.cmake @@ -0,0 +1,21 @@ +# Set system vars + +if (CMAKE_SYSTEM_NAME MATCHES "Linux") + set(LINUX TRUE) +endif(CMAKE_SYSTEM_NAME MATCHES "Linux") + +if (CMAKE_SYSTEM_NAME MATCHES "FreeBSD") + set(FREEBSD TRUE) +endif (CMAKE_SYSTEM_NAME MATCHES "FreeBSD") + +if (CMAKE_SYSTEM_NAME MATCHES "OpenBSD") + set(OPENBSD TRUE) +endif (CMAKE_SYSTEM_NAME MATCHES "OpenBSD") + +if (CMAKE_SYSTEM_NAME MATCHES "NetBSD") + set(NETBSD TRUE) +endif (CMAKE_SYSTEM_NAME MATCHES "NetBSD") + +if (CMAKE_SYSTEM_NAME MATCHES "(Solaris|SunOS)") + set(SOLARIS TRUE) +endif (CMAKE_SYSTEM_NAME MATCHES "(Solaris|SunOS)") diff --git a/examples/c/CMakeLists.txt b/examples/c/CMakeLists.txt new file mode 100644 index 0000000..01be2ad --- /dev/null +++ b/examples/c/CMakeLists.txt @@ -0,0 +1,67 @@ +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # +# ##### # # # # +# #### ##### ###### # # # # # # # # +# # # # # # ## # # # # # # +# # # # # ##### # # # # #### # ### # +# # # ##### # # # # # # # # # # # +# # # # # # ## # # # # # # # +# #### # ###### # # ##### ##### # # # +# # +# This file is part of openGJK. # +# # +# openGJK is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# any later version. # +# # +# openGJK is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See The # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with openGJK. If not, see . # +# # +# openGJK: open-source Gilbert-Johnson-Keerthi algorithm # +# Copyright (C) Mattia Montanari 2018 - 2019 # +# http://iel.eng.ox.ac.uk/?page_id=504 # +# # +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # + +project(openGJKdemo VERSION 1.0.0 LANGUAGES C) + +set(APPLICATION_NAME ${PROJECT_NAME}) +set(CMAKE_C_STANDARD 11) +set(TEST_NAME ${PROJECT_NAME}_CTEST) + +message( "[${PROJECT_NAME}] CMake setting ..") + +# Set source file +set(SOURCE_FILES main.c ) + +# Create the executable +add_executable(demo ${SOURCE_FILES}) + +# Copy input files for this example after build +add_custom_command( + TARGET demo POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/userP.dat + ${CMAKE_CURRENT_BINARY_DIR}/userP.dat ) +add_custom_command( + TARGET demo POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/userQ.dat + ${CMAKE_CURRENT_BINARY_DIR}/userQ.dat ) + +# PLATFORM-SPECIFIC SETTING +if (UNIX) + find_library(M_LIB m) + # Link to openGJK and math library + target_link_libraries(demo openGJKlib m) +else () + set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) + target_link_libraries(demo openGJKlib) +endif () + +message(STATUS "Completed CMake setting for ${PROJECT_NAME}" ) \ No newline at end of file diff --git a/example1_c/main.c b/examples/c/main.c similarity index 81% rename from example1_c/main.c rename to examples/c/main.c index 82701a6..7606bd1 100644 --- a/example1_c/main.c +++ b/examples/c/main.c @@ -1,177 +1,178 @@ -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * - * ##### # # # * - * #### ##### ###### # # # # # # # * - * # # # # # ## # # # # # * - * # # # # ##### # # # # #### # ### * - * # # ##### # # # # # # # # # # * - * # # # # # ## # # # # # # * - * #### # ###### # # ##### ##### # # * - * * - * This file is part of openGJK. * - * * - * openGJK is free software: you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation, either version 3 of the License, or * - * any later version. * - * * - * openGJK is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See The * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with Foobar. If not, see . * - * * - * openGJK: open-source Gilbert-Johnson-Keerthi algorithm * - * Copyright (C) Mattia Montanari 2018 - 2019 * - * http://iel.eng.ox.ac.uk/?page_id=504 * - * * - * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * - * * - * This file runs an example to illustrate how to invoke the openGJK lib * - * within a C program. An executable called 'demo' can be compiled with * - * CMake. This reads the coordinates of two polytopes from the input * - * files userP.dat and userQ.dat, respectively, and returns the minimum * - * distance between them computed using the openGJK library. * - * * - * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - -/** - * @file main.c - * @author Mattia Montanari - * @date April 2018 - * @brief File illustrating an application that invokes openGJK. - * - */ - -#define _CRT_HAS_CXX17 0 -#include - -/* For importing openGJK this is Step 1: include header in subfolder. */ -#include "openGJK/openGJK.h" - -#ifndef WIN32 -#define fscanf_s fscanf -#endif - -/** -* @brief Function for reading input file with body's coordinates. -* -*/ -int readinput ( const char *inputfile, double ***pts, int * out ) { - int npoints = 0; - int idx = 0; - FILE *fp; - - /* Open file. */ -#ifdef WIN32 - errno_t err; - if ((err = fopen_s(&fp, inputfile, "r")) != 0) { -#else - if ((fp = fopen(inputfile, "r")) == NULL) { -#endif - fprintf(stdout, "ERROR: input file %s not found!\n", inputfile); - fprintf(stdout, " -> The file must be in the folder from which this program is launched\n\n"); - return 1; - } - - /* Read number of input vertices. */ - if (fscanf_s(fp, "%d", &npoints) != 1) - return 1; - - /* Allocate memory. */ - double **arr = (double **)malloc(npoints * sizeof(double *)); - for (int i=0; i. * + * * + * openGJK: open-source Gilbert-Johnson-Keerthi algorithm * + * Copyright (C) Mattia Montanari 2018 - 2019 * + * http://iel.eng.ox.ac.uk/?page_id=504 * + * * + * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * + * * + * This file runs an example to illustrate how to invoke the openGJK lib * + * within a C program. An executable called 'demo' can be compiled with * + * CMake. This reads the coordinates of two polytopes from the input * + * files userP.dat and userQ.dat, respectively, and returns the minimum * + * distance between them computed using the openGJK library. * + * * + * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + + /** + * @file main.c + * @author Mattia Montanari + * @date April 2018 + * @brief File illustrating an application that invokes openGJK. + * + */ + +#define _CRT_HAS_CXX17 0 +#include +#include + + /* For importing openGJK this is Step 1: include header in subfolder. */ +#include "openGJK/openGJK.h" + +#ifndef WIN32 +#define fscanf_s fscanf +#endif + +/** +* @brief Function for reading input file with body's coordinates. +* +*/ +int readinput(const char *inputfile, double ***pts, int * out) { + int npoints = 0; + int idx = 0; + FILE *fp; + + /* Open file. */ +#ifdef WIN32 + errno_t err; + if ((err = fopen_s(&fp, inputfile, "r")) != 0) { +#else + if ((fp = fopen(inputfile, "r")) == NULL) { +#endif + fprintf(stdout, "ERROR: input file %s not found!\n", inputfile); + fprintf(stdout, " -> The file must be in the folder from which this program is launched\n\n"); + return 1; + } + + /* Read number of input vertices. */ + if (fscanf(fp, "%d", &npoints) != 1) + return 1; + + /* Allocate memory. */ + double **arr = (double **)malloc(npoints * sizeof(double *)); + for (int i = 0; i < npoints; i++) + arr[i] = (double *)malloc(3 * sizeof(double)); + + /* Read and store vertices' coordinates. */ + for (idx = 0; idx < npoints; idx++) + { + if (fscanf(fp, "%lf %lf %lf\n", &arr[idx][0], &arr[idx][1], &arr[idx][2]) != 3) + return 1; + } + + /* Close file. */ + fclose(fp); + + /* Pass pointers. */ + *pts = arr; + *out = idx; + + return (0); +} + + +/** +* @brief Main program of example1_c (described in Section 3.1 of the paper). +* +*/ +int main() { + /* Squared distance computed by openGJK. */ + double dd; + /* Structure of simplex used by openGJK. */ + struct simplex s; + /* Number of vertices defining body 1 and body 2, respectively. */ + int nvrtx1, + nvrtx2; + /* Structures of body 1 and body 2, respectively. */ + struct bd bd1; + struct bd bd2; + /* Specify name of input files for body 1 and body 2, respectively. */ + char inputfileA[40] = "userP.dat", + inputfileB[40] = "userQ.dat"; + /* Pointers to vertices' coordinates of body 1 and body 2, respectively. */ + double(**vrtx1) = NULL, + (**vrtx2) = NULL; + + /* For importing openGJK this is Step 2: adapt the data structure for the + * two bodies that will be passed to the GJK procedure. */ + + /* Import coordinates of object 1. */ + if (readinput(inputfileA, &vrtx1, &nvrtx1)) + return (1); + bd1.coord = vrtx1; + bd1.numpoints = nvrtx1; + + /* Import coordinates of object 2. */ + if (readinput(inputfileB, &vrtx2, &nvrtx2)) + return (1); + bd2.coord = vrtx2; + bd2.numpoints = nvrtx2; + + /* Initialise simplex as empty */ + s.nvrtx = 0; + +#ifdef DEBUG + /* Verify input of body A. */ + for (int i = 0; i < bd1.numpoints; ++i) { + printf("%.2f ", vrtx1[i][0]); + printf("%.2f ", vrtx1[i][1]); + printf("%.2f\n", bd1.coord[i][2]); + } + + /* Verify input of body B. */ + for (int i = 0; i < bd2.numpoints; ++i) { + printf("%.2f ", bd2.coord[i][0]); + printf("%.2f ", bd2.coord[i][1]); + printf("%.2f\n", bd2.coord[i][2]); + } +#endif + + /* For importing openGJK this is Step 3: invoke the GJK procedure. */ + /* Compute squared distance using GJK algorithm. */ + dd = gjk(bd1, bd2, &s); + + /* Print distance between objects. */ + printf("Distance between bodies %f\n", dd); + + /* Free memory */ + for (int i = 0; i < bd1.numpoints; i++) + free(bd1.coord[i]); + free(bd1.coord); + for (int i = 0; i < bd2.numpoints; i++) + free(bd2.coord[i]); + free(bd2.coord); + + return (0); +} diff --git a/example1_c/userP.dat b/examples/c/userP.dat similarity index 91% rename from example1_c/userP.dat rename to examples/c/userP.dat index 4d97faa..fa37eba 100644 --- a/example1_c/userP.dat +++ b/examples/c/userP.dat @@ -1,10 +1,10 @@ -9 -0.0 5.5 0.0 -2.3 1.0 -2.0 -8.1 4.0 2.4 -4.3 5.0 2.2 -2.5 1.0 2.3 -7.1 1.0 2.4 -1.0 1.5 0.3 -3.3 0.5 0.3 -6.0 1.4 0.2 +9 +0.0 5.5 0.0 +2.3 1.0 -2.0 +8.1 4.0 2.4 +4.3 5.0 2.2 +2.5 1.0 2.3 +7.1 1.0 2.4 +1.0 1.5 0.3 +3.3 0.5 0.3 +6.0 1.4 0.2 diff --git a/example1_c/userQ.dat b/examples/c/userQ.dat similarity index 93% rename from example1_c/userQ.dat rename to examples/c/userQ.dat index daaef2d..16e94a1 100644 --- a/example1_c/userQ.dat +++ b/examples/c/userQ.dat @@ -1,10 +1,10 @@ -9 --0.0 -5.5 0.0 --2.3 -1.0 2.0 --8.1 -4.0 -2.4 --4.3 -5.0 -2.2 --2.5 -1.0 -2.3 --7.1 -1.0 -2.4 --1.0 -1.5 -0.3 --3.3 -0.5 -0.3 --6.0 -1.4 -0.2 +9 +-0.0 -5.5 0.0 +-2.3 -1.0 2.0 +-8.1 -4.0 -2.4 +-4.3 -5.0 -2.2 +-2.5 -1.0 -2.3 +-7.1 -1.0 -2.4 +-1.0 -1.5 -0.3 +-3.3 -0.5 -0.3 +-6.0 -1.4 -0.2 diff --git a/example3_csharp/main.cs b/examples/cs/main.cs similarity index 93% rename from example3_csharp/main.cs rename to examples/cs/main.cs index a342be9..086fa1a 100644 --- a/example3_csharp/main.cs +++ b/examples/cs/main.cs @@ -1,67 +1,63 @@ -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * - * ##### # # # * - * #### ##### ###### # # # # # # # * - * # # # # # ## # # # # # * - * # # # # ##### # # # # #### # ### * - * # # ##### # # # # # # # # # # * - * # # # # # ## # # # # # # * - * #### # ###### # # ##### ##### # # * - * * - * This file is part of openGJK. * - * * - * openGJK is free software: you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation, either version 3 of the License, or * - * any later version. * - * * - * openGJK is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See The * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with Foobar. If not, see . * - * * - * openGJK: open-source Gilbert-Johnson-Keerthi algorithm * - * Copyright (C) Mattia Montanari 2018 - 2019 * - * http://iel.eng.ox.ac.uk/?page_id=504 * - * * - * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - -using System; - -using System.Runtime.InteropServices; - -public class Tester -{ - - -#if UNIX - [DllImport("libopenGJKlib.so", EntryPoint="csFunction", CallingConvention = CallingConvention.StdCall)] -#else - [DllImport("openGJKlib", EntryPoint = "csFunction", CallingConvention = CallingConvention.StdCall)] -#endif - static extern double gjk(int na, double [,] ia, int nb, double [,] ib); - - public static void Main(string[] args) - { - double dist; - // Define array A with coordinates - int nCoordsA = 9; - var inCoordsA = new double[3,9] { {0.0 , 2.3 , 8.1 , 4.3 ,2.5 , 7.1 , 1.0 , 3.3 , 6.0} , { 5.5 , 1.0 , 4.0 , 5.0 ,1.0, 1.0, 1.5, 0.5 , 1.4} ,{ 0.0 , -2.0, 2.4, 2.2, 2.3 , 2.4 , 0.3 , 0.3 , 0.2} }; - - // Define array B with coordinates - int nCoordsB = 9; - var inCoordsB = new double[3,9] { {-0.0 , -2.3 , -8.1 , -4.3 ,-2.5 , -7.1 , -1.0 , -3.3 , -6.0} , { -5.5 , -1.0 ,- 4.0 ,- 5.0 ,-1.0, -1.0, -1.5, -0.5 , -1.4} ,{ -0.0 , 2.0, -2.4, -2.2, -2.3 , -2.4 , -0.3 , -0.3 , -0.2} }; - - // Invoke GJK to compute distance - dist = gjk( nCoordsA, inCoordsA, nCoordsB, inCoordsB ); - - // Output results - var s = string.Format("{0:0.##}", dist); - var message = string.Format("The distance between {0} is {1}","A and B",s); - Console.WriteLine(message); - Console.WriteLine("Press any key to exit"); - Console.ReadLine(); - } -} +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * + * ##### # # # * + * #### ##### ###### # # # # # # # * + * # # # # # ## # # # # # * + * # # # # ##### # # # # #### # ### * + * # # ##### # # # # # # # # # # * + * # # # # # ## # # # # # # * + * #### # ###### # # ##### ##### # # * + * * + * This file is part of openGJK. * + * * + * openGJK is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * any later version. * + * * + * openGJK is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See The * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with Foobar. If not, see . * + * * + * openGJK: open-source Gilbert-Johnson-Keerthi algorithm * + * Copyright (C) Mattia Montanari 2018 - 2019 * + * http://iel.eng.ox.ac.uk/?page_id=504 * + * * + * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +using System; + +using System.Runtime.InteropServices; + +public class Tester +{ + + [DllImport("libopenGJKlib", EntryPoint="csFunction", CallingConvention = CallingConvention.StdCall)] + + static extern double gjk(int na, double [,] ia, int nb, double [,] ib); + + public static void Main(string[] args) + { + double dist; + // Define array A with coordinates + int nCoordsA = 9; + var inCoordsA = new double[3,9] { {0.0 , 2.3 , 8.1 , 4.3 ,2.5 , 7.1 , 1.0 , 3.3 , 6.0} , { 5.5 , 1.0 , 4.0 , 5.0 ,1.0, 1.0, 1.5, 0.5 , 1.4} ,{ 0.0 , -2.0, 2.4, 2.2, 2.3 , 2.4 , 0.3 , 0.3 , 0.2} }; + + // Define array B with coordinates + int nCoordsB = 9; + var inCoordsB = new double[3,9] { {-0.0 , -2.3 , -8.1 , -4.3 ,-2.5 , -7.1 , -1.0 , -3.3 , -6.0} , { -5.5 , -1.0 ,- 4.0 ,- 5.0 ,-1.0, -1.0, -1.5, -0.5 , -1.4} ,{ -0.0 , 2.0, -2.4, -2.2, -2.3 , -2.4 , -0.3 , -0.3 , -0.2} }; + + // Invoke GJK to compute distance + dist = gjk( nCoordsA, inCoordsA, nCoordsB, inCoordsB ); + + // Output results + var s = string.Format("{0:0.##}", dist); + var message = string.Format("The distance between {0} is {1}","A and B",s); + Console.WriteLine(message); + Console.WriteLine("Press any key to exit"); + Console.ReadLine(); + } +} diff --git a/examples/cython/openGJK_cython.pxd b/examples/cython/openGJK_cython.pxd new file mode 100644 index 0000000..ea7a1ae --- /dev/null +++ b/examples/cython/openGJK_cython.pxd @@ -0,0 +1,44 @@ +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # +# ##### # # # # +# #### ##### ###### # # # # # # # # +# # # # # # ## # # # # # # +# # # # # ##### # # # # #### # ### # +# # # ##### # # # # # # # # # # # +# # # # # # ## # # # # # # # +# #### # ###### # # ##### ##### # # # +# # +# This file is part of openGJK. # +# # +# OpenGJK is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# any later version. # +# # +# OpenGJK is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See The # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with OpenGJK. If not, see . # +# # +# openGJK: open-source Gilbert-Johnson-Keerthi algorithm # +# Copyright (C) Mattia Montanari 2018 - 2020 # +# http://iel.eng.ox.ac.uk/?page_id=504 # +# # +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # + +# Declare C function and data types +cdef extern from "openGJK.h": + struct bd: + int numpoints + double s[3] + double ** coord + + struct simplex: + int nvrtx + double vrtx[4][3] + int wids[4] + double lambdas[4] + + double gjk(bd bd1, bd bd2, simplex *s) diff --git a/examples/cython/openGJK_cython.pyx b/examples/cython/openGJK_cython.pyx new file mode 100644 index 0000000..4ee60e5 --- /dev/null +++ b/examples/cython/openGJK_cython.pyx @@ -0,0 +1,111 @@ +#!python +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # +# ##### # # # # +# #### ##### ###### # # # # # # # # +# # # # # # ## # # # # # # +# # # # # ##### # # # # #### # ### # +# # # ##### # # # # # # # # # # # +# # # # # # ## # # # # # # # +# #### # ###### # # ##### ##### # # # +# # +# This file is part of openGJK. # +# # +# OpenGJK is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# any later version. # +# # +# OpenGJK is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See The # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with OpenGJK. If not, see . # +# # +# openGJK: open-source Gilbert-Johnson-Keerthi algorithm # +# Copyright (C) Mattia Montanari 2018 - 2020 # +# http://iel.eng.ox.ac.uk/?page_id=504 # +# # +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # + +# cython: language_level=3 +# distutils: sources = ../../src/openGJK.c +# distutils: include_dirs = ../../include/openGJK + +cimport openGJK_cython + +import numpy as np +from libc.stdlib cimport free, malloc +from cpython.mem cimport PyMem_Malloc, PyMem_Free + +# Create Python function +def pygjk(bod1, bod2): + + # Declare data types + cdef: + simplex s + bd bd1 + bd bd2 + double dist2 + + # Convert 1D array to 2D, if any + if bod1.ndim < 2: + bod1 = np.append([bod1], [[1.,1.,1.]], axis = 0) + bd1.numpoints = np.size(bod1,0) - 1 + else: + bd1.numpoints = np.size(bod1,0) + + + if bod2.ndim < 2: + bod2 = np.append([bod2], [[1.,1.,1.]], axis = 0) + bd2.numpoints = np.size(bod2,0) - 1 + else: + bd2.numpoints = np.size(bod2,0) + + + # Allocate memory for bodies + bd1.coord = malloc(bd1.numpoints * sizeof(double *)) + if not bd1.coord: + raise NameError('Not enough memory for bd1.coord') + for i in range(0, bd1.numpoints): + bd1.coord[i] = malloc(3 * sizeof(double)) + if not bd1.coord[i]: + raise NameError('Not enough memory for bd1.coord[]') + + bd2.coord = malloc(bd2.numpoints * sizeof(double *)) + if not bd2.coord: + raise NameError('Not enough memory for bd2.coord') + for j in range(0, bd2.numpoints): + bd2.coord[j] = malloc(3 * sizeof(double)) + if not bd2.coord[j]: + raise NameError('Not enough memory for bd2.coord[]') + + # Create numpy-array MemoryView + cdef: + double [:,:] narr1 = bod1 + double [:,:] narr2 = bod2 + + # Assign coordinate values + for i in range(0, bd1.numpoints): + for j in range(0,3): + bd1.coord[i][j] = narr1[i,j] + + for i in range(0, bd2.numpoints): + for j in range(0,3): + bd2.coord[i][j] = narr2[i,j] + + # Call C function + dist2 = gjk(bd1, bd2, &s) + + # Free the memory + for ii in range(0, bd1.numpoints): + free(bd1.coord[ii]) + free(bd1.coord) + + for jj in range(0, bd2.numpoints): + free(bd2.coord[jj]) + free(bd2.coord) + + return dist2 + diff --git a/examples/cython/pygjk_trial.py b/examples/cython/pygjk_trial.py new file mode 100644 index 0000000..3b68b7a --- /dev/null +++ b/examples/cython/pygjk_trial.py @@ -0,0 +1,38 @@ +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # +# ##### # # # # +# #### ##### ###### # # # # # # # # +# # # # # # ## # # # # # # +# # # # # ##### # # # # #### # ### # +# # # ##### # # # # # # # # # # # +# # # # # # ## # # # # # # # +# #### # ###### # # ##### ##### # # # +# # +# This file is part of openGJK. # +# # +# OpenGJK is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# any later version. # +# # +# OpenGJK is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See The # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with OpenGJK. If not, see . # +# # +# openGJK: open-source Gilbert-Johnson-Keerthi algorithm # +# Copyright (C) Mattia Montanari 2018 - 2020 # +# http://iel.eng.ox.ac.uk/?page_id=504 # +# # +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # + +import numpy as np +import openGJK_cython as opengjk + +a = np.array([[1.,1.,1.],[1.,1.,1.]]) +b = np.array([[11.,1.,1.],[1.,1.,1.]]) +d = opengjk.pygjk(a,b) + +print(d) \ No newline at end of file diff --git a/examples/cython/setup.py b/examples/cython/setup.py new file mode 100644 index 0000000..801ff67 --- /dev/null +++ b/examples/cython/setup.py @@ -0,0 +1,44 @@ +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # +# ##### # # # # +# #### ##### ###### # # # # # # # # +# # # # # # ## # # # # # # +# # # # # ##### # # # # #### # ### # +# # # ##### # # # # # # # # # # # +# # # # # # ## # # # # # # # +# #### # ###### # # ##### ##### # # # +# # +# This file is part of openGJK. # +# # +# OpenGJK is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# any later version. # +# # +# OpenGJK is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See The # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with OpenGJK. If not, see . # +# # +# openGJK: open-source Gilbert-Johnson-Keerthi algorithm # +# Copyright (C) Mattia Montanari 2018 - 2020 # +# http://iel.eng.ox.ac.uk/?page_id=504 # +# # +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # + +from setuptools import Extension, setup +from Cython.Build import cythonize + +exts = Extension( + "openGJK_cython", + sources = ["openGJK_cython.pyx"], + extra_compile_args=['-I../../include/','-fopenmp'], + extra_link_args=['-fopenmp'], +) + +setup( + name='openGJK-cython-version', + ext_modules = cythonize( [exts] ) +) \ No newline at end of file diff --git a/examples/cython/test.py b/examples/cython/test.py new file mode 100644 index 0000000..aba5508 --- /dev/null +++ b/examples/cython/test.py @@ -0,0 +1,185 @@ +import openGJK_cython as opengjk +from scipy.spatial.transform import Rotation as R +import numpy as np +import pytest +#from IPython import embed + +def settol(): + return 1e-12 + +def distance_point_to_line_3D(P1, P2, point): + """ + distance from point to line + """ + return np.linalg.norm(np.cross(P2-P1, P1-point))/np.linalg.norm(P2-P1) + + +def distance_point_to_plane_3D(P1, P2, P3, point): + """ + Distance from point to plane + """ + return np.abs(np.dot(np.cross(P2-P1, P3-P1) / + np.linalg.norm(np.cross(P2-P1, P3-P1)), point-P2)) + + +@pytest.mark.parametrize("delta", [0.1, 1e-12, 0, -2]) +def test_line_point_distance(delta): + line = np.array([[0.1, 0.2, 0.3], [0.5, 0.8, 0.7]], dtype=np.float64) + point_on_line = line[0] + 0.27*(line[1]-line[0]) + normal = np.cross(line[0], line[1]) + point = point_on_line + delta * normal + distance = opengjk.pygjk(line, point) + actual_distance = distance_point_to_line_3D( + line[0], line[1], point) + print(distance, actual_distance) + assert(np.isclose(distance, actual_distance, atol=settol() )) + + +@pytest.mark.parametrize("delta", [0.1, 1e-12, 0]) +def test_line_line_distance(delta): + line = np.array([[-0.5, -0.7, -0.3], [1, 2, 3]], dtype=np.float64) + point_on_line = line[0] + 0.38*(line[1]-line[0]) + normal = np.cross(line[0], line[1]) + point = point_on_line + delta * normal + line_2 = np.array([point, [2, 5, 6]], dtype=np.float64) + distance = opengjk.pygjk(line, line_2) + actual_distance = distance_point_to_line_3D( + line[0], line[1], line_2[0]) + print(distance, actual_distance) + assert(np.isclose(distance, actual_distance, atol=settol() )) + + +@pytest.mark.parametrize("delta", [0.1**(3*i) for i in range(6)]) +def test_tri_distance(delta): + tri_1 = np.array([[0, 0, 0], [1, 0, 0], [0, 1, 0]], dtype=np.float64) + tri_2 = np.array([[1, delta, 0], [3, 1.2, 0], [ + 1, 1, 0]], dtype=np.float64) + P1 = tri_1[2] + P2 = tri_1[1] + point = tri_2[0] + actual_distance = distance_point_to_line_3D(P1, P2, point) + distance = opengjk.pygjk(tri_1, tri_2) + print("Computed distance ", distance, "Actual distance ", actual_distance) + + #embed() + assert(np.isclose(distance, actual_distance, atol=settol() )) + + +@pytest.mark.parametrize("delta", [0.1*0.1**(3*i) for i in range(6)]) +def test_quad_distance2d(delta): + quad_1 = np.array([[0, 0, 0], [1, 0, 0], [0, 1, 0], + [1, 1, 0]], dtype=np.float64) + quad_2 = np.array([[0, 1+delta, 0], [2, 2, 0], + [2, 4, 0], [4, 4, 0]], dtype=np.float64) + P1 = quad_1[2] + P2 = quad_1[3] + point = quad_2[0] + actual_distance = distance_point_to_line_3D(P1, P2, point) + distance = opengjk.pygjk(quad_1, quad_2) + print("Computed distance ", distance, "Actual distance ", actual_distance) + + assert(np.isclose(distance, actual_distance, atol=settol() )) + + +@pytest.mark.parametrize("delta", [1*0.5**(3*i) for i in range(7)]) +def test_tetra_distance_3d(delta): + tetra_1 = np.array([[0, 0, 0.2], [1, 0, 0.1], [0, 1, 0.3], + [0, 0, 1]], dtype=np.float64) + tetra_2 = np.array([[0, 0, -3], [1, 0, -3], [0, 1, -3], + [0.5, 0.3, -delta]], dtype=np.float64) + actual_distance = distance_point_to_plane_3D(tetra_1[0], tetra_1[1], + tetra_1[2], tetra_2[3]) + distance = opengjk.pygjk(tetra_1, tetra_2) + print("Computed distance ", distance, "Actual distance ", actual_distance) + + assert(np.isclose(distance, actual_distance, atol=settol() )) + + +@pytest.mark.parametrize("delta", [(-1)**i*np.sqrt(2)*0.1**(3*i) + for i in range(6)]) +def test_tetra_collision_3d(delta): + tetra_1 = np.array([[0, 0, 0], [1, 0, 0], [0, 1, 0], + [0, 0, 1]], dtype=np.float64) + tetra_2 = np.array([[0, 0, -3], [1, 0, -3], [0, 1, -3], + [0.5, 0.3, -delta]], dtype=np.float64) + actual_distance = distance_point_to_plane_3D(tetra_1[0], tetra_1[1], + tetra_1[2], tetra_2[3]) + distance = opengjk.pygjk(tetra_1, tetra_2) + + if delta < 0: + assert(np.isclose(distance, 0, atol=settol())) + else: + print("Computed distance ", distance, + "Actual distance ", actual_distance) + assert(np.isclose(distance, actual_distance, atol=settol())) + + +@pytest.mark.parametrize("delta", [0, -0.1, -0.49, -0.51]) +def test_hex_collision_3d(delta): + hex_1 = np.array([[0, 0, 0], [1, 0, 0], [0, 1, 0], [1, 1, 0], + [0, 0, 1], [1, 0, 1], [0, 1, 1], [1, 1, 1]], + dtype=np.float64) + P0 = np.array([1.5+delta, 1.5+delta, 0.5], dtype=np.float64) + P1 = np.array([2, 2, 1], dtype=np.float64) + P2 = np.array([2, 1.25, 0.25], dtype=np.float64) + P3 = P1 + P2 - P0 + quad_1 = np.array([P0, P1, P2, P3], dtype=np.float64) + n = (np.cross(quad_1[1]-quad_1[0], quad_1[2]-quad_1[0]) / + np.linalg.norm( + np.cross(quad_1[1]-quad_1[0], + quad_1[2]-quad_1[0]))) + quad_2 = quad_1 + n + hex_2 = np.zeros((8, 3), dtype=np.float64) + hex_2[:4, :] = quad_1 + hex_2[4:, :] = quad_2 + actual_distance = np.linalg.norm( + np.array([1, 1, P0[2]], dtype=np.float64)-hex_2[0]) + distance = opengjk.pygjk(hex_1, hex_2) + + if P0[0] < 1: + assert(np.isclose(distance, 0, atol=settol())) + else: + print("Computed distance ", distance, + "Actual distance ", actual_distance) + assert(np.isclose(distance, actual_distance, atol=settol())) + + +@pytest.mark.parametrize("c0", [0, 1, 2, 3]) +@pytest.mark.parametrize("c1", [0, 1, 2, 3]) +def test_cube_distance(c0, c1): + cubes = [np.array([[-1, -1, -1], [1, -1, -1], [-1, 1, -1], [1, 1, -1], + [-1, -1, 1], [1, -1, 1], [-1, 1, 1], [1, 1, 1]], + dtype=np.float64)] + + r = R.from_euler('z', 45, degrees=True) + cubes.append(r.apply(cubes[0])) + r = R.from_euler('y', np.arctan2(1.0, np.sqrt(2))) + cubes.append(r.apply(cubes[1])) + r = R.from_euler('y', 45, degrees=True) + cubes.append(r.apply(cubes[0])) + + dx = cubes[c0][:,0].max() - cubes[c1][:,0].min() + cube0 = cubes[c0] + + for delta in [1e8, 1.0, 1e-4, 1e-8, 1e-12]: + cube1 = cubes[c1] + np.array([dx + delta, 0, 0]) + distance = opengjk.pygjk(cube0, cube1) + print(distance, delta) + assert(np.isclose(distance, delta)) + +def test_random_objects(): + for i in range(1, 8): + for j in range(1, 8): + for k in range(1000): + arr1 = np.random.rand(i, 3) + arr2 = np.random.rand(j, 3) + opengjk.pygjk(arr1, arr2) + + +def test_large_random_objects(): + for i in range(1, 8): + for j in range(1, 8): + for k in range(1000): + arr1 = 10000.0*np.random.rand(i, 3) + arr2 = 10000.0*np.random.rand(j, 3) + opengjk.pygjk(arr1, arr2) diff --git a/example2_mex/main.m b/examples/matlab/main.m similarity index 98% rename from example2_mex/main.m rename to examples/matlab/main.m index b979c8b..b128667 100644 --- a/example2_mex/main.m +++ b/examples/matlab/main.m @@ -1,78 +1,78 @@ -% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % -% ##### # # # % -% #### ##### ###### # # # # # # # % -% # # # # # ## # # # # # % -% # # # # ##### # # # # #### # ### % -% # # ##### # # # # # # # # # # % -% # # # # # ## # # # # # # % -% #### # ###### # # ##### ##### # # % -% % -% This file is part of openGJK. % -% % -% openGJK is free software: you can redistribute it and/or modify % -% it under the terms of the GNU General Public License as published by % -% the Free Software Foundation, either version 3 of the License, or % -% any later version. % -% % -% openGJK is distributed in the hope that it will be useful, % -% but WITHOUT ANY WARRANTY; without even the implied warranty of % -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See The % -% GNU General Public License for more details. % -% % -% You should have received a copy of the GNU General Public License % -% along with Foobar. If not, see . % -% % -% openGJK: open-source Gilbert-Johnson-Keerthi algorithm % -% Copyright (C) Mattia Montanari 2018 - 2019 % -% http://iel.eng.ox.ac.uk/?page_id=504 % -% % -% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % -% % -% This file runs an example to illustrate how to cll the openGJK library % -% withing Matlab. It assumes that a mex file openGJK is availalbe, see % -% the runme.m script for information on how to compile it. % -% The example computes the minimum distance between two polytopes in 3D, % -% A and B, both defined as a list of points. % -% % -% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % - -% DEFINE BODY A AS 3xN MATRIX, WHERE N IS THE NUMBER OF VERTICES OF BODY A -A = [ 0.0 2.3 8.1 4.3 2.5 7.1 1.0 3.3 6.0 - 5.5 1.0 4.0 5.0 1.0 1.0 1.5 0.5 1.4 - 0.0 -2.0 2.4 2.2 2.3 2.4 0.3 0.3 0.2]; - -% DEFINE BODY B IN THE OPPOSITE QUADRANT OF BODY A -B = -A; - -% COMPUTE MINIMUM DISTANCE AND RETURN VALUE -dist = openGJK( A, B ); -fprintf('The minimum distance between A and B is %.2f\n',dist); - -% VISUALISE RESULTS -% .. create new figure -figure('units','centimeters', 'WindowStyle','normal', 'color','w',... - 'Position',[0 8.5 9 6],'defaultAxesColorOrder',parula,... - 'Renderer','opengl') -% .. adjust properties -axis equal tight off; hold all; -% .. display body A -DT = delaunayTriangulation(A'); -[K,~] = convexHull(DT); -trisurf(K,DT.Points(:,1),DT.Points(:,2),DT.Points(:,3),... - 'EdgeColor','none','FaceColor',[.4 1 .9 ],... - 'FaceLighting','flat' ) -% .. display body B -DT = delaunayTriangulation(B'); -[K,~] = convexHull(DT); -trisurf(K,DT.Points(:,1),DT.Points(:,2),DT.Points(:,3),... - 'EdgeColor','none','FaceColor',[.4 1 .8 ],... - 'FaceLighting','flat' ) -% .. represent the computed distance as a sphere -[x,y,z] = sphere(100); -surf(x.*dist/2,y.*dist/2,z.*dist/2,'facecolor',[.9 .9 .9],... - 'EdgeColor','none','FaceLighting','flat','SpecularColorReflectance',0,... - 'SpecularStrength',1,'SpecularExponent',10,'facealpha',.7) -% ... adjust point of view -view(42,21) -% ... add light -light('Position',[5 -10 20],'Style','local'); +% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % +% ##### # # # % +% #### ##### ###### # # # # # # # % +% # # # # # ## # # # # # % +% # # # # ##### # # # # #### # ### % +% # # ##### # # # # # # # # # # % +% # # # # # ## # # # # # # % +% #### # ###### # # ##### ##### # # % +% % +% This file is part of openGJK. % +% % +% openGJK is free software: you can redistribute it and/or modify % +% it under the terms of the GNU General Public License as published by % +% the Free Software Foundation, either version 3 of the License, or % +% any later version. % +% % +% openGJK is distributed in the hope that it will be useful, % +% but WITHOUT ANY WARRANTY; without even the implied warranty of % +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See The % +% GNU General Public License for more details. % +% % +% You should have received a copy of the GNU General Public License % +% along with Foobar. If not, see . % +% % +% openGJK: open-source Gilbert-Johnson-Keerthi algorithm % +% Copyright (C) Mattia Montanari 2018 - 2019 % +% http://iel.eng.ox.ac.uk/?page_id=504 % +% % +% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % +% % +% This file runs an example to illustrate how to cll the openGJK library % +% withing Matlab. It assumes that a mex file openGJK is availalbe, see % +% the runme.m script for information on how to compile it. % +% The example computes the minimum distance between two polytopes in 3D, % +% A and B, both defined as a list of points. % +% % +% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % + +% DEFINE BODY A AS 3xN MATRIX, WHERE N IS THE NUMBER OF VERTICES OF BODY A +A = [ 0.0 2.3 8.1 4.3 2.5 7.1 1.0 3.3 6.0 + 5.5 1.0 4.0 5.0 1.0 1.0 1.5 0.5 1.4 + 0.0 -2.0 2.4 2.2 2.3 2.4 0.3 0.3 0.2]; + +% DEFINE BODY B IN THE OPPOSITE QUADRANT OF BODY A +B = -A; + +% COMPUTE MINIMUM DISTANCE AND RETURN VALUE +dist = openGJK( A, B ); +fprintf('The minimum distance between A and B is %.2f\n',dist); + +% VISUALISE RESULTS +% .. create new figure +figure('units','centimeters', 'WindowStyle','normal', 'color','w',... + 'Position',[0 8.5 9 6],'defaultAxesColorOrder',parula,... + 'Renderer','opengl') +% .. adjust properties +axis equal tight off; hold all; +% .. display body A +DT = delaunayTriangulation(A'); +[K,~] = convexHull(DT); +trisurf(K,DT.Points(:,1),DT.Points(:,2),DT.Points(:,3),... + 'EdgeColor','none','FaceColor',[.4 1 .9 ],... + 'FaceLighting','flat' ) +% .. display body B +DT = delaunayTriangulation(B'); +[K,~] = convexHull(DT); +trisurf(K,DT.Points(:,1),DT.Points(:,2),DT.Points(:,3),... + 'EdgeColor','none','FaceColor',[.4 1 .8 ],... + 'FaceLighting','flat' ) +% .. represent the computed distance as a sphere +[x,y,z] = sphere(100); +surf(x.*dist/2,y.*dist/2,z.*dist/2,'facecolor',[.9 .9 .9],... + 'EdgeColor','none','FaceLighting','flat','SpecularColorReflectance',0,... + 'SpecularStrength',1,'SpecularExponent',10,'facealpha',.7) +% ... adjust point of view +view(42,21) +% ... add light +light('Position',[5 -10 20],'Style','local'); diff --git a/example2_mex/runme.m b/examples/matlab/runme.m similarity index 94% rename from example2_mex/runme.m rename to examples/matlab/runme.m index a90f6d8..ff6e21c 100644 --- a/example2_mex/runme.m +++ b/examples/matlab/runme.m @@ -1,79 +1,79 @@ -% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % -% ##### # # # % -% #### ##### ###### # # # # # # # % -% # # # # # ## # # # # # % -% # # # # ##### # # # # #### # ### % -% # # ##### # # # # # # # # # # % -% # # # # # ## # # # # # # % -% #### # ###### # # ##### ##### # # % -% % -% This file is part of openGJK. % -% % -% openGJK is free software: you can redistribute it and/or modify % -% it under the terms of the GNU General Public License as published by % -% the Free Software Foundation, either version 3 of the License, or % -% any later version. % -% % -% openGJK is distributed in the hope that it will be useful, % -% but WITHOUT ANY WARRANTY; without even the implied warranty of % -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See The % -% GNU General Public License for more details. % -% % -% You should have received a copy of the GNU General Public License % -% along with Foobar. If not, see . % -% % -% openGJK: open-source Gilbert-Johnson-Keerthi algorithm % -% Copyright (C) Mattia Montanari 2018 - 2019 % -% http://iel.eng.ox.ac.uk/?page_id=504 % -% % -% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % -% % -% This file compiles a mex function from the openGJK library and runs an % -% example. If the mex function cannot be compiled an error is returned. % -% % -% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % - -% CLEAR ALL VARIABLES -clearvars - -% SELECT OPTIMISATION FLAG - FASTER BUT NOT SUITABLE FOR DEBUGGING -if 0 - optflug = '-g'; %#ok<*UNRCH> -else - optflug = '-O'; -end -% SELECT SILET COMPILATION MODE. -if 1 - silflag = '-silent'; -else - silflag = '-v'; -end - -% TRY COMPILING MEX FILE -fprintf('Compiling mex function... ') -try -mex(fullfile('..','lib','src','openGJK.c'),... % Source of openGJK - '-largeArrayDims', ... % Support large arrays - optflug, ... % Compiler flag for debug/optimisation - fullfile('-I..','lib','include'),... % Folder to header files - '-outdir', pwd,... % Ouput directory for writing mex function - '-output', 'openGJK',... % Name of ouput mex file - '-DMATLABDOESMEXSTUFF',... % Define variable for mex function in source files - silflag ) % Silent/verbose flag - - % File compiled without errors. Return path and name of mex file - fprintf('completed!\n') - fprintf('The following mex file has been generated:') - fprintf('\t%s\n',[pwd,filesep,'openGJK.',mexext]) -catch - % Build failed, refer to documentation - fprintf('\n\n ERROR DETECTED! Mex file cannot be compiled.\n') - fprintf('\tFor more information, see ') - fprintf('this documentation page.\n\n') - return -end - -% RUN EXAMPLE -fprintf('Running example... ') -main +% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % +% ##### # # # % +% #### ##### ###### # # # # # # # % +% # # # # # ## # # # # # % +% # # # # ##### # # # # #### # ### % +% # # ##### # # # # # # # # # # % +% # # # # # ## # # # # # # % +% #### # ###### # # ##### ##### # # % +% % +% This file is part of openGJK. % +% % +% openGJK is free software: you can redistribute it and/or modify % +% it under the terms of the GNU General Public License as published by % +% the Free Software Foundation, either version 3 of the License, or % +% any later version. % +% % +% openGJK is distributed in the hope that it will be useful, % +% but WITHOUT ANY WARRANTY; without even the implied warranty of % +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See The % +% GNU General Public License for more details. % +% % +% You should have received a copy of the GNU General Public License % +% along with Foobar. If not, see . % +% % +% openGJK: open-source Gilbert-Johnson-Keerthi algorithm % +% Copyright (C) Mattia Montanari 2018 - 2019 % +% http://iel.eng.ox.ac.uk/?page_id=504 % +% % +% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % +% % +% This file compiles a mex function from the openGJK library and runs an % +% example. If the mex function cannot be compiled an error is returned. % +% % +% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % + +% CLEAR ALL VARIABLES +clearvars + +% SELECT OPTIMISATION FLAG - FASTER BUT NOT SUITABLE FOR DEBUGGING +if 0 + optflug = '-g'; %#ok<*UNRCH> +else + optflug = '-O'; +end +% SELECT SILET COMPILATION MODE. +if 1 + silflag = '-silent'; +else + silflag = '-v'; +end + +% TRY COMPILING MEX FILE +fprintf('Compiling mex function... ') +try +mex(fullfile('..','..','src','openGJK.c'),... % Source of openGJK + '-largeArrayDims', ... % Support large arrays + optflug, ... % Compiler flag for debug/optimisation + fullfile('-I..','..','include'),... % Folder to header files + '-outdir', pwd,... % Ouput directory for writing mex function + '-output', 'openGJK',... % Name of ouput mex file + '-DMATLABDOESMEXSTUFF',... % Define variable for mex function in source files + silflag ) % Silent/verbose flag + + % File compiled without errors. Return path and name of mex file + fprintf('completed!\n') + fprintf('The following mex file has been generated:') + fprintf('\t%s\n',[pwd,filesep,'openGJK.',mexext]) +catch + % Build failed, refer to documentation + fprintf('\n\n ERROR DETECTED! Mex file cannot be compiled.\n') + fprintf('\tFor more information, see ') + fprintf('this documentation page.\n\n') + return +end + +% RUN EXAMPLE +fprintf('Running example... ') +main fprintf('completed!\n') \ No newline at end of file diff --git a/examples/python/build.sh b/examples/python/build.sh new file mode 100755 index 0000000..b789d71 --- /dev/null +++ b/examples/python/build.sh @@ -0,0 +1,2 @@ +#!/bin/bash +g++ -Wall -fPIC -fopenmp -shared `python3 -m pybind11 --includes` -I ../../include -I/usr/include/eigen3 pyopenGJK.cpp ../../src/openGJK.c -o opengjkc`python3-config --extension-suffix` \ No newline at end of file diff --git a/examples/python/pyopenGJK.cpp b/examples/python/pyopenGJK.cpp new file mode 100644 index 0000000..f1a69d1 --- /dev/null +++ b/examples/python/pyopenGJK.cpp @@ -0,0 +1,31 @@ +#include "openGJK/openGJK.h" +#include +#include +namespace py = pybind11; + +PYBIND11_MODULE(opengjkc, m) +{ + m.def("gjk", + [](Eigen::Array& arr1, + Eigen::Array& arr2) + -> double { + struct simplex s; + struct bd bd1; + struct bd bd2; + bd1.numpoints = arr1.rows(); + std::vector arr1_rows(arr1.rows()); + for (int i = 0; i < arr1.rows(); ++i) + arr1_rows[i] = arr1.row(i).data(); + bd1.coord = arr1_rows.data(); + + bd2.numpoints = arr2.rows(); + std::vector arr2_rows(arr2.rows()); + for (int i = 0; i < arr2.rows(); ++i) + arr2_rows[i] = arr2.row(i).data(); + bd2.coord = arr2_rows.data(); + + double a = gjk(bd1, bd2, &s); + + return a; + }); +} \ No newline at end of file diff --git a/examples/python/test.py b/examples/python/test.py new file mode 100644 index 0000000..e9fb20d --- /dev/null +++ b/examples/python/test.py @@ -0,0 +1,185 @@ +import opengjkc as opengjk +from scipy.spatial.transform import Rotation as R +import numpy as np +import pytest +#from IPython import embed + +def settol(): + return 1e-12 + +def distance_point_to_line_3D(P1, P2, point): + """ + distance from point to line + """ + return np.linalg.norm(np.cross(P2-P1, P1-point))/np.linalg.norm(P2-P1) + + +def distance_point_to_plane_3D(P1, P2, P3, point): + """ + Distance from point to plane + """ + return np.abs(np.dot(np.cross(P2-P1, P3-P1) / + np.linalg.norm(np.cross(P2-P1, P3-P1)), point-P2)) + + +@pytest.mark.parametrize("delta", [0.1, 1e-12, 0, -2]) +def test_line_point_distance(delta): + line = np.array([[0.1, 0.2, 0.3], [0.5, 0.8, 0.7]], dtype=np.float64) + point_on_line = line[0] + 0.27*(line[1]-line[0]) + normal = np.cross(line[0], line[1]) + point = point_on_line + delta * normal + distance = opengjk.gjk(line, point) + actual_distance = distance_point_to_line_3D( + line[0], line[1], point) + print(distance, actual_distance) + assert(np.isclose(distance, actual_distance, atol=settol() )) + + +@pytest.mark.parametrize("delta", [0.1, 1e-12, 0]) +def test_line_line_distance(delta): + line = np.array([[-0.5, -0.7, -0.3], [1, 2, 3]], dtype=np.float64) + point_on_line = line[0] + 0.38*(line[1]-line[0]) + normal = np.cross(line[0], line[1]) + point = point_on_line + delta * normal + line_2 = np.array([point, [2, 5, 6]], dtype=np.float64) + distance = opengjk.gjk(line, line_2) + actual_distance = distance_point_to_line_3D( + line[0], line[1], line_2[0]) + print(distance, actual_distance) + assert(np.isclose(distance, actual_distance, atol=settol() )) + + +@pytest.mark.parametrize("delta", [0.1**(3*i) for i in range(6)]) +def test_tri_distance(delta): + tri_1 = np.array([[0, 0, 0], [1, 0, 0], [0, 1, 0]], dtype=np.float64) + tri_2 = np.array([[1, delta, 0], [3, 1.2, 0], [ + 1, 1, 0]], dtype=np.float64) + P1 = tri_1[2] + P2 = tri_1[1] + point = tri_2[0] + actual_distance = distance_point_to_line_3D(P1, P2, point) + distance = opengjk.gjk(tri_1, tri_2) + print("Computed distance ", distance, "Actual distance ", actual_distance) + + #embed() + assert(np.isclose(distance, actual_distance, atol=settol() )) + + +@pytest.mark.parametrize("delta", [0.1*0.1**(3*i) for i in range(6)]) +def test_quad_distance2d(delta): + quad_1 = np.array([[0, 0, 0], [1, 0, 0], [0, 1, 0], + [1, 1, 0]], dtype=np.float64) + quad_2 = np.array([[0, 1+delta, 0], [2, 2, 0], + [2, 4, 0], [4, 4, 0]], dtype=np.float64) + P1 = quad_1[2] + P2 = quad_1[3] + point = quad_2[0] + actual_distance = distance_point_to_line_3D(P1, P2, point) + distance = opengjk.gjk(quad_1, quad_2) + print("Computed distance ", distance, "Actual distance ", actual_distance) + + assert(np.isclose(distance, actual_distance, atol=settol() )) + + +@pytest.mark.parametrize("delta", [1*0.5**(3*i) for i in range(7)]) +def test_tetra_distance_3d(delta): + tetra_1 = np.array([[0, 0, 0.2], [1, 0, 0.1], [0, 1, 0.3], + [0, 0, 1]], dtype=np.float64) + tetra_2 = np.array([[0, 0, -3], [1, 0, -3], [0, 1, -3], + [0.5, 0.3, -delta]], dtype=np.float64) + actual_distance = distance_point_to_plane_3D(tetra_1[0], tetra_1[1], + tetra_1[2], tetra_2[3]) + distance = opengjk.gjk(tetra_1, tetra_2) + print("Computed distance ", distance, "Actual distance ", actual_distance) + + assert(np.isclose(distance, actual_distance, atol=settol() )) + + +@pytest.mark.parametrize("delta", [(-1)**i*np.sqrt(2)*0.1**(3*i) + for i in range(6)]) +def test_tetra_collision_3d(delta): + tetra_1 = np.array([[0, 0, 0], [1, 0, 0], [0, 1, 0], + [0, 0, 1]], dtype=np.float64) + tetra_2 = np.array([[0, 0, -3], [1, 0, -3], [0, 1, -3], + [0.5, 0.3, -delta]], dtype=np.float64) + actual_distance = distance_point_to_plane_3D(tetra_1[0], tetra_1[1], + tetra_1[2], tetra_2[3]) + distance = opengjk.gjk(tetra_1, tetra_2) + + if delta < 0: + assert(np.isclose(distance, 0, atol=settol())) + else: + print("Computed distance ", distance, + "Actual distance ", actual_distance) + assert(np.isclose(distance, actual_distance, atol=settol())) + + +@pytest.mark.parametrize("delta", [0, -0.1, -0.49, -0.51]) +def test_hex_collision_3d(delta): + hex_1 = np.array([[0, 0, 0], [1, 0, 0], [0, 1, 0], [1, 1, 0], + [0, 0, 1], [1, 0, 1], [0, 1, 1], [1, 1, 1]], + dtype=np.float64) + P0 = np.array([1.5+delta, 1.5+delta, 0.5], dtype=np.float64) + P1 = np.array([2, 2, 1], dtype=np.float64) + P2 = np.array([2, 1.25, 0.25], dtype=np.float64) + P3 = P1 + P2 - P0 + quad_1 = np.array([P0, P1, P2, P3], dtype=np.float64) + n = (np.cross(quad_1[1]-quad_1[0], quad_1[2]-quad_1[0]) / + np.linalg.norm( + np.cross(quad_1[1]-quad_1[0], + quad_1[2]-quad_1[0]))) + quad_2 = quad_1 + n + hex_2 = np.zeros((8, 3), dtype=np.float64) + hex_2[:4, :] = quad_1 + hex_2[4:, :] = quad_2 + actual_distance = np.linalg.norm( + np.array([1, 1, P0[2]], dtype=np.float64)-hex_2[0]) + distance = opengjk.gjk(hex_1, hex_2) + + if P0[0] < 1: + assert(np.isclose(distance, 0, atol=settol())) + else: + print("Computed distance ", distance, + "Actual distance ", actual_distance) + assert(np.isclose(distance, actual_distance, atol=settol())) + + +@pytest.mark.parametrize("c0", [0, 1, 2, 3]) +@pytest.mark.parametrize("c1", [0, 1, 2, 3]) +def test_cube_distance(c0, c1): + cubes = [np.array([[-1, -1, -1], [1, -1, -1], [-1, 1, -1], [1, 1, -1], + [-1, -1, 1], [1, -1, 1], [-1, 1, 1], [1, 1, 1]], + dtype=np.float64)] + + r = R.from_euler('z', 45, degrees=True) + cubes.append(r.apply(cubes[0])) + r = R.from_euler('y', np.arctan2(1.0, np.sqrt(2))) + cubes.append(r.apply(cubes[1])) + r = R.from_euler('y', 45, degrees=True) + cubes.append(r.apply(cubes[0])) + + dx = cubes[c0][:,0].max() - cubes[c1][:,0].min() + cube0 = cubes[c0] + + for delta in [1e8, 1.0, 1e-4, 1e-8, 1e-12]: + cube1 = cubes[c1] + np.array([dx + delta, 0, 0]) + distance = opengjk.gjk(cube0, cube1) + print(distance, delta) + assert(np.isclose(distance, delta)) + +def test_random_objects(): + for i in range(1, 8): + for j in range(1, 8): + for k in range(1000): + arr1 = np.random.rand(i, 3) + arr2 = np.random.rand(j, 3) + opengjk.gjk(arr1, arr2) + + +def test_large_random_objects(): + for i in range(1, 8): + for j in range(1, 8): + for k in range(1000): + arr1 = 10000.0*np.random.rand(i, 3) + arr2 = 10000.0*np.random.rand(j, 3) + opengjk.gjk(arr1, arr2) diff --git a/include/openGJK/openGJK.h b/include/openGJK/openGJK.h new file mode 100644 index 0000000..71455f8 --- /dev/null +++ b/include/openGJK/openGJK.h @@ -0,0 +1,52 @@ +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * +* ##### # # # * +* #### ##### ###### # # # # # # # * +* # # # # # ## # # # # # * +* # # # # ##### # # # # #### # ### * +* # # ##### # # # # # # # # # # * +* # # # # # ## # # # # # # * +* #### # ###### # # ##### ##### # # * +* * +* Edward Garemo and Mattia Montanari * +* University of Oxford 2019 * +* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * +* * +* This is the header file for the openGJK.c file. It defines the openGJK * +* function and it two important structures: bd and simplex. * +* * +* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +#ifndef __OPENGJK_H__ +#define __OPENGJK_H__ + +#include +#include +#include "math.h" + +/** +* @brief Structure of a body. +*/ +struct bd { + int numpoints; /**< Number of points defining the body. */ + double s[3]; /**< Support mapping computed last. */ + double **coord; /**< Pointer to pointer to the points' coordinates. */ +}; + + +/** +* @brief Structure for a simplex. +*/ +struct simplex { + int nvrtx; /**< Number of simplex's vertices. */ + double vrtx[4][3]; /**< Coordinates of simplex's vertices. */ + int wids[4]; /**< Label of the simplex's vertices. */ + double lambdas[4]; /**< Barycentric coordiantes for each vertex. */ +}; + +/** + * @brief The GJK algorithm which returns the minimum distance between + * two bodies. + */ +extern double gjk(struct bd, struct bd, struct simplex *); + +#endif \ No newline at end of file diff --git a/lib/ext/predicates.c b/lib/ext/predicates.c deleted file mode 100644 index 95bead5..0000000 --- a/lib/ext/predicates.c +++ /dev/null @@ -1,4271 +0,0 @@ -/*****************************************************************************/ -/* */ -/* Routines for Arbitrary Precision Floating-point Arithmetic */ -/* and Fast Robust Geometric Predicates */ -/* (predicates.c) */ -/* */ -/* May 18, 1996 */ -/* */ -/* Placed in the public domain by */ -/* Jonathan Richard Shewchuk */ -/* School of Computer Science */ -/* Carnegie Mellon University */ -/* 5000 Forbes Avenue */ -/* Pittsburgh, Pennsylvania 15213-3891 */ -/* jrs@cs.cmu.edu */ -/* */ -/* This file contains C implementation of algorithms for exact addition */ -/* and multiplication of floating-point numbers, and predicates for */ -/* robustly performing the orientation and incircle tests used in */ -/* computational geometry. The algorithms and underlying theory are */ -/* described in Jonathan Richard Shewchuk. "Adaptive Precision Floating- */ -/* Point Arithmetic and Fast Robust Geometric Predicates." Technical */ -/* Report CMU-CS-96-140, School of Computer Science, Carnegie Mellon */ -/* University, Pittsburgh, Pennsylvania, May 1996. (Submitted to */ -/* Discrete & Computational Geometry.) */ -/* */ -/* This file, the paper listed above, and other information are available */ -/* from the Web page http://www.cs.cmu.edu/~quake/robust.html . */ -/* */ -/*****************************************************************************/ - -/*****************************************************************************/ -/* */ -/* Using this code: */ -/* */ -/* First, read the short or long version of the paper (from the Web page */ -/* above). */ -/* */ -/* Be sure to call exactinit() once, before calling any of the arithmetic */ -/* functions or geometric predicates. Also be sure to turn on the */ -/* optimizer when compiling this file. */ -/* */ -/* */ -/* Several geometric predicates are defined. Their parameters are all */ -/* points. Each point is an array of two or three floating-point */ -/* numbers. The geometric predicates, described in the papers, are */ -/* */ -/* orient2d(pa, pb, pc) */ -/* orient2dfast(pa, pb, pc) */ -/* orient3d(pa, pb, pc, pd) */ -/* orient3dfast(pa, pb, pc, pd) */ -/* incircle(pa, pb, pc, pd) */ -/* incirclefast(pa, pb, pc, pd) */ -/* insphere(pa, pb, pc, pd, pe) */ -/* inspherefast(pa, pb, pc, pd, pe) */ -/* */ -/* Those with suffix "fast" are approximate, non-robust versions. Those */ -/* without the suffix are adaptive precision, robust versions. There */ -/* are also versions with the suffices "exact" and "slow", which are */ -/* non-adaptive, exact arithmetic versions, which I use only for timings */ -/* in my arithmetic papers. */ -/* */ -/* */ -/* An expansion is represented by an array of floating-point numbers, */ -/* sorted from smallest to largest magnitude (possibly with interspersed */ -/* zeros). The length of each expansion is stored as a separate integer, */ -/* and each arithmetic function returns an integer which is the length */ -/* of the expansion it created. */ -/* */ -/* Several arithmetic functions are defined. Their parameters are */ -/* */ -/* e, f Input expansions */ -/* elen, flen Lengths of input expansions (must be >= 1) */ -/* h Output expansion */ -/* b Input scalar */ -/* */ -/* The arithmetic functions are */ -/* */ -/* grow_expansion(elen, e, b, h) */ -/* grow_expansion_zeroelim(elen, e, b, h) */ -/* expansion_sum(elen, e, flen, f, h) */ -/* expansion_sum_zeroelim1(elen, e, flen, f, h) */ -/* expansion_sum_zeroelim2(elen, e, flen, f, h) */ -/* fast_expansion_sum(elen, e, flen, f, h) */ -/* fast_expansion_sum_zeroelim(elen, e, flen, f, h) */ -/* linear_expansion_sum(elen, e, flen, f, h) */ -/* linear_expansion_sum_zeroelim(elen, e, flen, f, h) */ -/* scale_expansion(elen, e, b, h) */ -/* scale_expansion_zeroelim(elen, e, b, h) */ -/* compress(elen, e, h) */ -/* */ -/* All of these are described in the long version of the paper; some are */ -/* described in the short version. All return an integer that is the */ -/* length of h. Those with suffix _zeroelim perform zero elimination, */ -/* and are recommended over their counterparts. The procedure */ -/* fast_expansion_sum_zeroelim() (or linear_expansion_sum_zeroelim() on */ -/* processors that do not use the round-to-even tiebreaking rule) is */ -/* recommended over expansion_sum_zeroelim(). Each procedure has a */ -/* little note next to it (in the code below) that tells you whether or */ -/* not the output expansion may be the same array as one of the input */ -/* expansions. */ -/* */ -/* */ -/* If you look around below, you'll also find macros for a bunch of */ -/* simple unrolled arithmetic operations, and procedures for printing */ -/* expansions (commented out because they don't work with all C */ -/* compilers) and for generating random floating-point numbers whose */ -/* significand bits are all random. Most of the macros have undocumented */ -/* requirements that certain of their parameters should not be the same */ -/* variable; for safety, better to make sure all the parameters are */ -/* distinct variables. Feel free to send email to jrs@cs.cmu.edu if you */ -/* have questions. */ -/* */ -/*****************************************************************************/ - -#include "predicates.h" - -/* On some machines, the exact arithmetic routines might be defeated by the */ -/* use of internal extended precision floating-point registers. Sometimes */ -/* this problem can be fixed by defining certain values to be volatile, */ -/* thus forcing them to be stored to memory and rounded off. This isn't */ -/* a great solution, though, as it slows the arithmetic down. */ -/* */ -/* To try this out, write "#define INEXACT volatile" below. Normally, */ -/* however, INEXACT should be defined to be nothing. ("#define INEXACT".) */ - -#define INEXACT /* Nothing */ -/* #define INEXACT volatile */ - -#define REAL double /* float or double */ -#define REALPRINT doubleprint -#define REALRAND doublerand -#define NARROWRAND narrowdoublerand -#define UNIFORMRAND uniformdoublerand - -/* Which of the following two methods of finding the absolute values is */ -/* fastest is compiler-dependent. A few compilers can inline and optimize */ -/* the fabs() call; but most will incur the overhead of a function call, */ -/* which is disastrously slow. A faster way on IEEE machines might be to */ -/* mask the appropriate bit, but that's difficult to do in C. */ - -#define Absolute(a) ((a) >= 0.0 ? (a) : -(a)) -/* #define Absolute(a) fabs(a) */ - -/* Many of the operations are broken up into two pieces, a main part that */ -/* performs an approximate operation, and a "tail" that computes the */ -/* roundoff error of that operation. */ -/* */ -/* The operations Fast_Two_Sum(), Fast_Two_Diff(), Two_Sum(), Two_Diff(), */ -/* Split(), and Two_Product() are all implemented as described in the */ -/* reference. Each of these macros requires certain variables to be */ -/* defined in the calling routine. The variables `bvirt', `c', `abig', */ -/* `_i', `_j', `_k', `_l', `_m', and `_n' are declared `INEXACT' because */ -/* they store the result of an operation that may incur roundoff error. */ -/* The input parameter `x' (or the highest numbered `x_' parameter) must */ -/* also be declared `INEXACT'. */ - -#define Fast_Two_Sum_Tail(a, b, x, y) \ - bvirt = x - a; \ - y = b - bvirt - -#define Fast_Two_Sum(a, b, x, y) \ - x = (REAL) (a + b); \ - Fast_Two_Sum_Tail(a, b, x, y) - -#define Fast_Two_Diff_Tail(a, b, x, y) \ - bvirt = a - x; \ - y = bvirt - b - -#define Fast_Two_Diff(a, b, x, y) \ - x = (REAL) (a - b); \ - Fast_Two_Diff_Tail(a, b, x, y) - -#define Two_Sum_Tail(a, b, x, y) \ - bvirt = (REAL) (x - a); \ - avirt = x - bvirt; \ - bround = b - bvirt; \ - around = a - avirt; \ - y = around + bround - -#define Two_Sum(a, b, x, y) \ - x = (REAL) (a + b); \ - Two_Sum_Tail(a, b, x, y) - -#define Two_Diff_Tail(a, b, x, y) \ - bvirt = (REAL) (a - x); \ - avirt = x + bvirt; \ - bround = bvirt - b; \ - around = a - avirt; \ - y = around + bround - -#define Two_Diff(a, b, x, y) \ - x = (REAL) (a - b); \ - Two_Diff_Tail(a, b, x, y) - -#define Split(a, ahi, alo) \ - c = (REAL) (splitter * a); \ - abig = (REAL) (c - a); \ - ahi = c - abig; \ - alo = a - ahi - -#define Two_Product_Tail(a, b, x, y) \ - Split(a, ahi, alo); \ - Split(b, bhi, blo); \ - err1 = x - (ahi * bhi); \ - err2 = err1 - (alo * bhi); \ - err3 = err2 - (ahi * blo); \ - y = (alo * blo) - err3 - -#define Two_Product(a, b, x, y) \ - x = (REAL) (a * b); \ - Two_Product_Tail(a, b, x, y) - -/* Two_Product_Presplit() is Two_Product() where one of the inputs has */ -/* already been split. Avoids redundant splitting. */ - -#define Two_Product_Presplit(a, b, bhi, blo, x, y) \ - x = (REAL) (a * b); \ - Split(a, ahi, alo); \ - err1 = x - (ahi * bhi); \ - err2 = err1 - (alo * bhi); \ - err3 = err2 - (ahi * blo); \ - y = (alo * blo) - err3 - -/* Two_Product_2Presplit() is Two_Product() where both of the inputs have */ -/* already been split. Avoids redundant splitting. */ - -#define Two_Product_2Presplit(a, ahi, alo, b, bhi, blo, x, y) \ - x = (REAL) (a * b); \ - err1 = x - (ahi * bhi); \ - err2 = err1 - (alo * bhi); \ - err3 = err2 - (ahi * blo); \ - y = (alo * blo) - err3 - -/* Square() can be done more quickly than Two_Product(). */ - -#define Square_Tail(a, x, y) \ - Split(a, ahi, alo); \ - err1 = x - (ahi * ahi); \ - err3 = err1 - ((ahi + ahi) * alo); \ - y = (alo * alo) - err3 - -#define Square(a, x, y) \ - x = (REAL) (a * a); \ - Square_Tail(a, x, y) - -/* Macros for summing expansions of various fixed lengths. These are all */ -/* unrolled versions of Expansion_Sum(). */ - -#define Two_One_Sum(a1, a0, b, x2, x1, x0) \ - Two_Sum(a0, b , _i, x0); \ - Two_Sum(a1, _i, x2, x1) - -#define Two_One_Diff(a1, a0, b, x2, x1, x0) \ - Two_Diff(a0, b , _i, x0); \ - Two_Sum( a1, _i, x2, x1) - -#define Two_Two_Sum(a1, a0, b1, b0, x3, x2, x1, x0) \ - Two_One_Sum(a1, a0, b0, _j, _0, x0); \ - Two_One_Sum(_j, _0, b1, x3, x2, x1) - -#define Two_Two_Diff(a1, a0, b1, b0, x3, x2, x1, x0) \ - Two_One_Diff(a1, a0, b0, _j, _0, x0); \ - Two_One_Diff(_j, _0, b1, x3, x2, x1) - -#define Four_One_Sum(a3, a2, a1, a0, b, x4, x3, x2, x1, x0) \ - Two_One_Sum(a1, a0, b , _j, x1, x0); \ - Two_One_Sum(a3, a2, _j, x4, x3, x2) - -#define Four_Two_Sum(a3, a2, a1, a0, b1, b0, x5, x4, x3, x2, x1, x0) \ - Four_One_Sum(a3, a2, a1, a0, b0, _k, _2, _1, _0, x0); \ - Four_One_Sum(_k, _2, _1, _0, b1, x5, x4, x3, x2, x1) - -#define Four_Four_Sum(a3, a2, a1, a0, b4, b3, b1, b0, x7, x6, x5, x4, x3, x2, \ - x1, x0) \ - Four_Two_Sum(a3, a2, a1, a0, b1, b0, _l, _2, _1, _0, x1, x0); \ - Four_Two_Sum(_l, _2, _1, _0, b4, b3, x7, x6, x5, x4, x3, x2) - -#define Eight_One_Sum(a7, a6, a5, a4, a3, a2, a1, a0, b, x8, x7, x6, x5, x4, \ - x3, x2, x1, x0) \ - Four_One_Sum(a3, a2, a1, a0, b , _j, x3, x2, x1, x0); \ - Four_One_Sum(a7, a6, a5, a4, _j, x8, x7, x6, x5, x4) - -#define Eight_Two_Sum(a7, a6, a5, a4, a3, a2, a1, a0, b1, b0, x9, x8, x7, \ - x6, x5, x4, x3, x2, x1, x0) \ - Eight_One_Sum(a7, a6, a5, a4, a3, a2, a1, a0, b0, _k, _6, _5, _4, _3, _2, \ - _1, _0, x0); \ - Eight_One_Sum(_k, _6, _5, _4, _3, _2, _1, _0, b1, x9, x8, x7, x6, x5, x4, \ - x3, x2, x1) - -#define Eight_Four_Sum(a7, a6, a5, a4, a3, a2, a1, a0, b4, b3, b1, b0, x11, \ - x10, x9, x8, x7, x6, x5, x4, x3, x2, x1, x0) \ - Eight_Two_Sum(a7, a6, a5, a4, a3, a2, a1, a0, b1, b0, _l, _6, _5, _4, _3, \ - _2, _1, _0, x1, x0); \ - Eight_Two_Sum(_l, _6, _5, _4, _3, _2, _1, _0, b4, b3, x11, x10, x9, x8, \ - x7, x6, x5, x4, x3, x2) - -/* Macros for multiplying expansions of various fixed lengths. */ - -#define Two_One_Product(a1, a0, b, x3, x2, x1, x0) \ - Split(b, bhi, blo); \ - Two_Product_Presplit(a0, b, bhi, blo, _i, x0); \ - Two_Product_Presplit(a1, b, bhi, blo, _j, _0); \ - Two_Sum(_i, _0, _k, x1); \ - Fast_Two_Sum(_j, _k, x3, x2) - -#define Four_One_Product(a3, a2, a1, a0, b, x7, x6, x5, x4, x3, x2, x1, x0) \ - Split(b, bhi, blo); \ - Two_Product_Presplit(a0, b, bhi, blo, _i, x0); \ - Two_Product_Presplit(a1, b, bhi, blo, _j, _0); \ - Two_Sum(_i, _0, _k, x1); \ - Fast_Two_Sum(_j, _k, _i, x2); \ - Two_Product_Presplit(a2, b, bhi, blo, _j, _0); \ - Two_Sum(_i, _0, _k, x3); \ - Fast_Two_Sum(_j, _k, _i, x4); \ - Two_Product_Presplit(a3, b, bhi, blo, _j, _0); \ - Two_Sum(_i, _0, _k, x5); \ - Fast_Two_Sum(_j, _k, x7, x6) - -#define Two_Two_Product(a1, a0, b1, b0, x7, x6, x5, x4, x3, x2, x1, x0) \ - Split(a0, a0hi, a0lo); \ - Split(b0, bhi, blo); \ - Two_Product_2Presplit(a0, a0hi, a0lo, b0, bhi, blo, _i, x0); \ - Split(a1, a1hi, a1lo); \ - Two_Product_2Presplit(a1, a1hi, a1lo, b0, bhi, blo, _j, _0); \ - Two_Sum(_i, _0, _k, _1); \ - Fast_Two_Sum(_j, _k, _l, _2); \ - Split(b1, bhi, blo); \ - Two_Product_2Presplit(a0, a0hi, a0lo, b1, bhi, blo, _i, _0); \ - Two_Sum(_1, _0, _k, x1); \ - Two_Sum(_2, _k, _j, _1); \ - Two_Sum(_l, _j, _m, _2); \ - Two_Product_2Presplit(a1, a1hi, a1lo, b1, bhi, blo, _j, _0); \ - Two_Sum(_i, _0, _n, _0); \ - Two_Sum(_1, _0, _i, x2); \ - Two_Sum(_2, _i, _k, _1); \ - Two_Sum(_m, _k, _l, _2); \ - Two_Sum(_j, _n, _k, _0); \ - Two_Sum(_1, _0, _j, x3); \ - Two_Sum(_2, _j, _i, _1); \ - Two_Sum(_l, _i, _m, _2); \ - Two_Sum(_1, _k, _i, x4); \ - Two_Sum(_2, _i, _k, x5); \ - Two_Sum(_m, _k, x7, x6) - -/* An expansion of length two can be squared more quickly than finding the */ -/* product of two different expansions of length two, and the result is */ -/* guaranteed to have no more than six (rather than eight) components. */ - -#define Two_Square(a1, a0, x5, x4, x3, x2, x1, x0) \ - Square(a0, _j, x0); \ - _0 = a0 + a0; \ - Two_Product(a1, _0, _k, _1); \ - Two_One_Sum(_k, _1, _j, _l, _2, x1); \ - Square(a1, _j, _1); \ - Two_Two_Sum(_j, _1, _l, _2, x5, x4, x3, x2) - -REAL splitter; /* = 2^ceiling(p / 2) + 1. Used to split floats in half. */ -REAL epsilon; /* = 2^(-p). Used to estimate roundoff errors. */ -/* A set of coefficients used to calculate maximum roundoff errors. */ -REAL resulterrbound; -REAL ccwerrboundA, ccwerrboundB, ccwerrboundC; -REAL o3derrboundA, o3derrboundB, o3derrboundC; -REAL iccerrboundA, iccerrboundB, iccerrboundC; -REAL isperrboundA, isperrboundB, isperrboundC; - -/*****************************************************************************/ -/* */ -/* doubleprint() Print the bit representation of a double. */ -/* */ -/* Useful for debugging exact arithmetic routines. */ -/* */ -/*****************************************************************************/ - -/* -void doubleprint(number) -double number; -{ - unsigned long long no; - unsigned long long sign, expo; - int exponent; - int i, bottomi; - - no = *(unsigned long long *) &number; - sign = no & 0x8000000000000000ll; - expo = (no >> 52) & 0x7ffll; - exponent = (int) expo; - exponent = exponent - 1023; - if (sign) { - printf("-"); - } else { - printf(" "); - } - if (exponent == -1023) { - printf( - "0.0000000000000000000000000000000000000000000000000000_ ( )"); - } else { - printf("1."); - bottomi = -1; - for (i = 0; i < 52; i++) { - if (no & 0x0008000000000000ll) { - printf("1"); - bottomi = i; - } else { - printf("0"); - } - no <<= 1; - } - printf("_%d (%d)", exponent, exponent - 1 - bottomi); - } -} -*/ - -/*****************************************************************************/ -/* */ -/* floatprint() Print the bit representation of a float. */ -/* */ -/* Useful for debugging exact arithmetic routines. */ -/* */ -/*****************************************************************************/ - -/* -void floatprint(number) -float number; -{ - unsigned no; - unsigned sign, expo; - int exponent; - int i, bottomi; - - no = *(unsigned *) &number; - sign = no & 0x80000000; - expo = (no >> 23) & 0xff; - exponent = (int) expo; - exponent = exponent - 127; - if (sign) { - printf("-"); - } else { - printf(" "); - } - if (exponent == -127) { - printf("0.00000000000000000000000_ ( )"); - } else { - printf("1."); - bottomi = -1; - for (i = 0; i < 23; i++) { - if (no & 0x00400000) { - printf("1"); - bottomi = i; - } else { - printf("0"); - } - no <<= 1; - } - printf("_%3d (%3d)", exponent, exponent - 1 - bottomi); - } -} -*/ - -/*****************************************************************************/ -/* */ -/* expansion_print() Print the bit representation of an expansion. */ -/* */ -/* Useful for debugging exact arithmetic routines. */ -/* */ -/*****************************************************************************/ - -/* -void expansion_print(elen, e) -int elen; -REAL *e; -{ - int i; - - for (i = elen - 1; i >= 0; i--) { - REALPRINT(e[i]); - if (i > 0) { - printf(" +\n"); - } else { - printf("\n"); - } - } -} -*/ - -/*****************************************************************************/ -/* */ -/* doublerand() Generate a double with random 53-bit significand and a */ -/* random exponent in [0, 511]. */ -/* */ -/*****************************************************************************/ - -double doublerand() -{ - double result; - double expo; - long a, b, c; - long i; - - a = rand(); - b = rand(); - c = rand(); - result = (double) (a - 1073741824) * 8388608.0 + (double) (b >> 8); - for (i = 512, expo = 2; i <= 131072; i *= 2, expo = expo * expo) { - if (c & i) { - result *= expo; - } - } - return result; -} - -/*****************************************************************************/ -/* */ -/* narrowdoublerand() Generate a double with random 53-bit significand */ -/* and a random exponent in [0, 7]. */ -/* */ -/*****************************************************************************/ - -double narrowdoublerand() -{ - double result; - double expo; - long a, b, c; - long i; - - a = rand(); - b = rand(); - c = rand(); - result = (double) (a - 1073741824) * 8388608.0 + (double) (b >> 8); - for (i = 512, expo = 2; i <= 2048; i *= 2, expo = expo * expo) { - if (c & i) { - result *= expo; - } - } - return result; -} - -/*****************************************************************************/ -/* */ -/* uniformdoublerand() Generate a double with random 53-bit significand. */ -/* */ -/*****************************************************************************/ - -double uniformdoublerand() -{ - double result; - long a, b; - - a = rand(); - b = rand(); - result = (double) (a - 1073741824) * 8388608.0 + (double) (b >> 8); - return result; -} - -/*****************************************************************************/ -/* */ -/* floatrand() Generate a float with random 24-bit significand and a */ -/* random exponent in [0, 63]. */ -/* */ -/*****************************************************************************/ - -float floatrand() -{ - float result; - float expo; - long a, c; - long i; - - a = rand(); - c = rand(); - result = (float) ((a - 1073741824) >> 6); - for (i = 512, expo = 2; i <= 16384; i *= 2, expo = expo * expo) { - if (c & i) { - result *= expo; - } - } - return result; -} - -/*****************************************************************************/ -/* */ -/* narrowfloatrand() Generate a float with random 24-bit significand and */ -/* a random exponent in [0, 7]. */ -/* */ -/*****************************************************************************/ - -float narrowfloatrand() -{ - float result; - float expo; - long a, c; - long i; - - a = rand(); - c = rand(); - result = (float) ((a - 1073741824) >> 6); - for (i = 512, expo = 2; i <= 2048; i *= 2, expo = expo * expo) { - if (c & i) { - result *= expo; - } - } - return result; -} - -/*****************************************************************************/ -/* */ -/* uniformfloatrand() Generate a float with random 24-bit significand. */ -/* */ -/*****************************************************************************/ - -float uniformfloatrand() -{ - float result; - long a; - - a = rand(); - result = (float) ((a - 1073741824) >> 6); - return result; -} - -/*****************************************************************************/ -/* */ -/* exactinit() Initialize the variables used for exact arithmetic. */ -/* */ -/* `epsilon' is the largest power of two such that 1.0 + epsilon = 1.0 in */ -/* floating-point arithmetic. `epsilon' bounds the relative roundoff */ -/* error. It is used for floating-point error analysis. */ -/* */ -/* `splitter' is used to split floating-point numbers into two half- */ -/* length significands for exact multiplication. */ -/* */ -/* I imagine that a highly optimizing compiler might be too smart for its */ -/* own good, and somehow cause this routine to fail, if it pretends that */ -/* floating-point arithmetic is too much like real arithmetic. */ -/* */ -/* Don't change this routine unless you fully understand it. */ -/* */ -/*****************************************************************************/ - -void exactinit() -{ - REAL half; - REAL check, lastcheck; - int every_other; - - every_other = 1; - half = 0.5; - epsilon = 1.0; - splitter = 1.0; - check = 1.0; - /* Repeatedly divide `epsilon' by two until it is too small to add to */ - /* one without causing roundoff. (Also check if the sum is equal to */ - /* the previous sum, for machines that round up instead of using exact */ - /* rounding. Not that this library will work on such machines anyway. */ - do { - lastcheck = check; - epsilon *= half; - if (every_other) { - splitter *= 2.0; - } - every_other = !every_other; - check = 1.0 + epsilon; - } while ((check != 1.0) && (check != lastcheck)); - splitter += 1.0; - - /* Error bounds for orientation and incircle tests. */ - resulterrbound = (3.0 + 8.0 * epsilon) * epsilon; - ccwerrboundA = (3.0 + 16.0 * epsilon) * epsilon; - ccwerrboundB = (2.0 + 12.0 * epsilon) * epsilon; - ccwerrboundC = (9.0 + 64.0 * epsilon) * epsilon * epsilon; - o3derrboundA = (7.0 + 56.0 * epsilon) * epsilon; - o3derrboundB = (3.0 + 28.0 * epsilon) * epsilon; - o3derrboundC = (26.0 + 288.0 * epsilon) * epsilon * epsilon; - iccerrboundA = (10.0 + 96.0 * epsilon) * epsilon; - iccerrboundB = (4.0 + 48.0 * epsilon) * epsilon; - iccerrboundC = (44.0 + 576.0 * epsilon) * epsilon * epsilon; - isperrboundA = (16.0 + 224.0 * epsilon) * epsilon; - isperrboundB = (5.0 + 72.0 * epsilon) * epsilon; - isperrboundC = (71.0 + 1408.0 * epsilon) * epsilon * epsilon; -} - -/*****************************************************************************/ -/* */ -/* grow_expansion() Add a scalar to an expansion. */ -/* */ -/* Sets h = e + b. See the long version of my paper for details. */ -/* */ -/* Maintains the nonoverlapping property. If round-to-even is used (as */ -/* with IEEE 754), maintains the strongly nonoverlapping and nonadjacent */ -/* properties as well. (That is, if e has one of these properties, so */ -/* will h.) */ -/* */ -/*****************************************************************************/ - -int grow_expansion(elen, e, b, h) /* e and h can be the same. */ - int elen; - REAL *e; - REAL b; - REAL *h; -{ - REAL Q; - INEXACT REAL Qnew; - int eindex; - REAL enow; - INEXACT REAL bvirt; - REAL avirt, bround, around; - - Q = b; - for (eindex = 0; eindex < elen; eindex++) { - enow = e[eindex]; - Two_Sum(Q, enow, Qnew, h[eindex]); - Q = Qnew; - } - h[eindex] = Q; - return eindex + 1; -} - -/*****************************************************************************/ -/* */ -/* grow_expansion_zeroelim() Add a scalar to an expansion, eliminating */ -/* zero components from the output expansion. */ -/* */ -/* Sets h = e + b. See the long version of my paper for details. */ -/* */ -/* Maintains the nonoverlapping property. If round-to-even is used (as */ -/* with IEEE 754), maintains the strongly nonoverlapping and nonadjacent */ -/* properties as well. (That is, if e has one of these properties, so */ -/* will h.) */ -/* */ -/*****************************************************************************/ - -int grow_expansion_zeroelim(elen, e, b, h) /* e and h can be the same. */ - int elen; - REAL *e; - REAL b; - REAL *h; -{ - REAL Q, hh; - INEXACT REAL Qnew; - int eindex, hindex; - REAL enow; - INEXACT REAL bvirt; - REAL avirt, bround, around; - - hindex = 0; - Q = b; - for (eindex = 0; eindex < elen; eindex++) { - enow = e[eindex]; - Two_Sum(Q, enow, Qnew, hh); - Q = Qnew; - if (hh != 0.0) { - h[hindex++] = hh; - } - } - if ((Q != 0.0) || (hindex == 0)) { - h[hindex++] = Q; - } - return hindex; -} - -/*****************************************************************************/ -/* */ -/* expansion_sum() Sum two expansions. */ -/* */ -/* Sets h = e + f. See the long version of my paper for details. */ -/* */ -/* Maintains the nonoverlapping property. If round-to-even is used (as */ -/* with IEEE 754), maintains the nonadjacent property as well. (That is, */ -/* if e has one of these properties, so will h.) Does NOT maintain the */ -/* strongly nonoverlapping property. */ -/* */ -/*****************************************************************************/ - -int expansion_sum(elen, e, flen, f, h) -/* e and h can be the same, but f and h cannot. */ - int elen; - REAL *e; - int flen; - REAL *f; - REAL *h; -{ - REAL Q; - INEXACT REAL Qnew; - int findex, hindex, hlast; - REAL hnow; - INEXACT REAL bvirt; - REAL avirt, bround, around; - - Q = f[0]; - for (hindex = 0; hindex < elen; hindex++) { - hnow = e[hindex]; - Two_Sum(Q, hnow, Qnew, h[hindex]); - Q = Qnew; - } - h[hindex] = Q; - hlast = hindex; - for (findex = 1; findex < flen; findex++) { - Q = f[findex]; - for (hindex = findex; hindex <= hlast; hindex++) { - hnow = h[hindex]; - Two_Sum(Q, hnow, Qnew, h[hindex]); - Q = Qnew; - } - h[++hlast] = Q; - } - return hlast + 1; -} - -/*****************************************************************************/ -/* */ -/* expansion_sum_zeroelim1() Sum two expansions, eliminating zero */ -/* components from the output expansion. */ -/* */ -/* Sets h = e + f. See the long version of my paper for details. */ -/* */ -/* Maintains the nonoverlapping property. If round-to-even is used (as */ -/* with IEEE 754), maintains the nonadjacent property as well. (That is, */ -/* if e has one of these properties, so will h.) Does NOT maintain the */ -/* strongly nonoverlapping property. */ -/* */ -/*****************************************************************************/ - -int expansion_sum_zeroelim1(elen, e, flen, f, h) -/* e and h can be the same, but f and h cannot. */ - int elen; - REAL *e; - int flen; - REAL *f; - REAL *h; -{ - REAL Q; - INEXACT REAL Qnew; - int index, findex, hindex, hlast; - REAL hnow; - INEXACT REAL bvirt; - REAL avirt, bround, around; - - Q = f[0]; - for (hindex = 0; hindex < elen; hindex++) { - hnow = e[hindex]; - Two_Sum(Q, hnow, Qnew, h[hindex]); - Q = Qnew; - } - h[hindex] = Q; - hlast = hindex; - for (findex = 1; findex < flen; findex++) { - Q = f[findex]; - for (hindex = findex; hindex <= hlast; hindex++) { - hnow = h[hindex]; - Two_Sum(Q, hnow, Qnew, h[hindex]); - Q = Qnew; - } - h[++hlast] = Q; - } - hindex = -1; - for (index = 0; index <= hlast; index++) { - hnow = h[index]; - if (hnow != 0.0) { - h[++hindex] = hnow; - } - } - if (hindex == -1) { - return 1; - } else { - return hindex + 1; - } -} - -/*****************************************************************************/ -/* */ -/* expansion_sum_zeroelim2() Sum two expansions, eliminating zero */ -/* components from the output expansion. */ -/* */ -/* Sets h = e + f. See the long version of my paper for details. */ -/* */ -/* Maintains the nonoverlapping property. If round-to-even is used (as */ -/* with IEEE 754), maintains the nonadjacent property as well. (That is, */ -/* if e has one of these properties, so will h.) Does NOT maintain the */ -/* strongly nonoverlapping property. */ -/* */ -/*****************************************************************************/ - -int expansion_sum_zeroelim2(elen, e, flen, f, h) -/* e and h can be the same, but f and h cannot. */ - int elen; - REAL *e; - int flen; - REAL *f; - REAL *h; -{ - REAL Q, hh; - INEXACT REAL Qnew; - int eindex, findex, hindex, hlast; - REAL enow; - INEXACT REAL bvirt; - REAL avirt, bround, around; - - hindex = 0; - Q = f[0]; - for (eindex = 0; eindex < elen; eindex++) { - enow = e[eindex]; - Two_Sum(Q, enow, Qnew, hh); - Q = Qnew; - if (hh != 0.0) { - h[hindex++] = hh; - } - } - h[hindex] = Q; - hlast = hindex; - for (findex = 1; findex < flen; findex++) { - hindex = 0; - Q = f[findex]; - for (eindex = 0; eindex <= hlast; eindex++) { - enow = h[eindex]; - Two_Sum(Q, enow, Qnew, hh); - Q = Qnew; - if (hh != 0) { - h[hindex++] = hh; - } - } - h[hindex] = Q; - hlast = hindex; - } - return hlast + 1; -} - -/*****************************************************************************/ -/* */ -/* fast_expansion_sum() Sum two expansions. */ -/* */ -/* Sets h = e + f. See the long version of my paper for details. */ -/* */ -/* If round-to-even is used (as with IEEE 754), maintains the strongly */ -/* nonoverlapping property. (That is, if e is strongly nonoverlapping, h */ -/* will be also.) Does NOT maintain the nonoverlapping or nonadjacent */ -/* properties. */ -/* */ -/*****************************************************************************/ - -int fast_expansion_sum(elen, e, flen, f, h) /* h cannot be e or f. */ - int elen; - REAL *e; - int flen; - REAL *f; - REAL *h; -{ - REAL Q; - INEXACT REAL Qnew; - INEXACT REAL bvirt; - REAL avirt, bround, around; - int eindex, findex, hindex; - REAL enow, fnow; - - enow = e[0]; - fnow = f[0]; - eindex = findex = 0; - if ((fnow > enow) == (fnow > -enow)) { - Q = enow; - enow = e[++eindex]; - } else { - Q = fnow; - fnow = f[++findex]; - } - hindex = 0; - if ((eindex < elen) && (findex < flen)) { - if ((fnow > enow) == (fnow > -enow)) { - Fast_Two_Sum(enow, Q, Qnew, h[0]); - enow = e[++eindex]; - } else { - Fast_Two_Sum(fnow, Q, Qnew, h[0]); - fnow = f[++findex]; - } - Q = Qnew; - hindex = 1; - while ((eindex < elen) && (findex < flen)) { - if ((fnow > enow) == (fnow > -enow)) { - Two_Sum(Q, enow, Qnew, h[hindex]); - enow = e[++eindex]; - } else { - Two_Sum(Q, fnow, Qnew, h[hindex]); - fnow = f[++findex]; - } - Q = Qnew; - hindex++; - } - } - while (eindex < elen) { - Two_Sum(Q, enow, Qnew, h[hindex]); - enow = e[++eindex]; - Q = Qnew; - hindex++; - } - while (findex < flen) { - Two_Sum(Q, fnow, Qnew, h[hindex]); - fnow = f[++findex]; - Q = Qnew; - hindex++; - } - h[hindex] = Q; - return hindex + 1; -} - -/*****************************************************************************/ -/* */ -/* fast_expansion_sum_zeroelim() Sum two expansions, eliminating zero */ -/* components from the output expansion. */ -/* */ -/* Sets h = e + f. See the long version of my paper for details. */ -/* */ -/* If round-to-even is used (as with IEEE 754), maintains the strongly */ -/* nonoverlapping property. (That is, if e is strongly nonoverlapping, h */ -/* will be also.) Does NOT maintain the nonoverlapping or nonadjacent */ -/* properties. */ -/* */ -/*****************************************************************************/ - -int fast_expansion_sum_zeroelim(elen, e, flen, f, h) /* h cannot be e or f. */ - int elen; - REAL *e; - int flen; - REAL *f; - REAL *h; -{ - REAL Q; - INEXACT REAL Qnew; - INEXACT REAL hh; - INEXACT REAL bvirt; - REAL avirt, bround, around; - int eindex, findex, hindex; - REAL enow, fnow; - - enow = e[0]; - fnow = f[0]; - eindex = findex = 0; - if ((fnow > enow) == (fnow > -enow)) { - Q = enow; - enow = e[++eindex]; - } else { - Q = fnow; - fnow = f[++findex]; - } - hindex = 0; - if ((eindex < elen) && (findex < flen)) { - if ((fnow > enow) == (fnow > -enow)) { - Fast_Two_Sum(enow, Q, Qnew, hh); - enow = e[++eindex]; - } else { - Fast_Two_Sum(fnow, Q, Qnew, hh); - fnow = f[++findex]; - } - Q = Qnew; - if (hh != 0.0) { - h[hindex++] = hh; - } - while ((eindex < elen) && (findex < flen)) { - if ((fnow > enow) == (fnow > -enow)) { - Two_Sum(Q, enow, Qnew, hh); - enow = e[++eindex]; - } else { - Two_Sum(Q, fnow, Qnew, hh); - fnow = f[++findex]; - } - Q = Qnew; - if (hh != 0.0) { - h[hindex++] = hh; - } - } - } - while (eindex < elen) { - Two_Sum(Q, enow, Qnew, hh); - enow = e[++eindex]; - Q = Qnew; - if (hh != 0.0) { - h[hindex++] = hh; - } - } - while (findex < flen) { - Two_Sum(Q, fnow, Qnew, hh); - fnow = f[++findex]; - Q = Qnew; - if (hh != 0.0) { - h[hindex++] = hh; - } - } - if ((Q != 0.0) || (hindex == 0)) { - h[hindex++] = Q; - } - return hindex; -} - -/*****************************************************************************/ -/* */ -/* linear_expansion_sum() Sum two expansions. */ -/* */ -/* Sets h = e + f. See either version of my paper for details. */ -/* */ -/* Maintains the nonoverlapping property. (That is, if e is */ -/* nonoverlapping, h will be also.) */ -/* */ -/*****************************************************************************/ - -int linear_expansion_sum(elen, e, flen, f, h) /* h cannot be e or f. */ - int elen; - REAL *e; - int flen; - REAL *f; - REAL *h; -{ - REAL Q, q; - INEXACT REAL Qnew; - INEXACT REAL R; - INEXACT REAL bvirt; - REAL avirt, bround, around; - int eindex, findex, hindex; - REAL enow, fnow; - REAL g0; - - enow = e[0]; - fnow = f[0]; - eindex = findex = 0; - if ((fnow > enow) == (fnow > -enow)) { - g0 = enow; - enow = e[++eindex]; - } else { - g0 = fnow; - fnow = f[++findex]; - } - if ((eindex < elen) && ((findex >= flen) - || ((fnow > enow) == (fnow > -enow)))) { - Fast_Two_Sum(enow, g0, Qnew, q); - enow = e[++eindex]; - } else { - Fast_Two_Sum(fnow, g0, Qnew, q); - fnow = f[++findex]; - } - Q = Qnew; - for (hindex = 0; hindex < elen + flen - 2; hindex++) { - if ((eindex < elen) && ((findex >= flen) - || ((fnow > enow) == (fnow > -enow)))) { - Fast_Two_Sum(enow, q, R, h[hindex]); - enow = e[++eindex]; - } else { - Fast_Two_Sum(fnow, q, R, h[hindex]); - fnow = f[++findex]; - } - Two_Sum(Q, R, Qnew, q); - Q = Qnew; - } - h[hindex] = q; - h[hindex + 1] = Q; - return hindex + 2; -} - -/*****************************************************************************/ -/* */ -/* linear_expansion_sum_zeroelim() Sum two expansions, eliminating zero */ -/* components from the output expansion. */ -/* */ -/* Sets h = e + f. See either version of my paper for details. */ -/* */ -/* Maintains the nonoverlapping property. (That is, if e is */ -/* nonoverlapping, h will be also.) */ -/* */ -/*****************************************************************************/ - -int linear_expansion_sum_zeroelim(elen, e, flen, f, h)/* h cannot be e or f. */ - int elen; - REAL *e; - int flen; - REAL *f; - REAL *h; -{ - REAL Q, q, hh; - INEXACT REAL Qnew; - INEXACT REAL R; - INEXACT REAL bvirt; - REAL avirt, bround, around; - int eindex, findex, hindex; - int count; - REAL enow, fnow; - REAL g0; - - enow = e[0]; - fnow = f[0]; - eindex = findex = 0; - hindex = 0; - if ((fnow > enow) == (fnow > -enow)) { - g0 = enow; - enow = e[++eindex]; - } else { - g0 = fnow; - fnow = f[++findex]; - } - if ((eindex < elen) && ((findex >= flen) - || ((fnow > enow) == (fnow > -enow)))) { - Fast_Two_Sum(enow, g0, Qnew, q); - enow = e[++eindex]; - } else { - Fast_Two_Sum(fnow, g0, Qnew, q); - fnow = f[++findex]; - } - Q = Qnew; - for (count = 2; count < elen + flen; count++) { - if ((eindex < elen) && ((findex >= flen) - || ((fnow > enow) == (fnow > -enow)))) { - Fast_Two_Sum(enow, q, R, hh); - enow = e[++eindex]; - } else { - Fast_Two_Sum(fnow, q, R, hh); - fnow = f[++findex]; - } - Two_Sum(Q, R, Qnew, q); - Q = Qnew; - if (hh != 0) { - h[hindex++] = hh; - } - } - if (q != 0) { - h[hindex++] = q; - } - if ((Q != 0.0) || (hindex == 0)) { - h[hindex++] = Q; - } - return hindex; -} - -/*****************************************************************************/ -/* */ -/* scale_expansion() Multiply an expansion by a scalar. */ -/* */ -/* Sets h = be. See either version of my paper for details. */ -/* */ -/* Maintains the nonoverlapping property. If round-to-even is used (as */ -/* with IEEE 754), maintains the strongly nonoverlapping and nonadjacent */ -/* properties as well. (That is, if e has one of these properties, so */ -/* will h.) */ -/* */ -/*****************************************************************************/ - -int scale_expansion(elen, e, b, h) /* e and h cannot be the same. */ - int elen; - REAL *e; - REAL b; - REAL *h; -{ - INEXACT REAL Q; - INEXACT REAL sum; - INEXACT REAL product1; - REAL product0; - int eindex, hindex; - REAL enow; - INEXACT REAL bvirt; - REAL avirt, bround, around; - INEXACT REAL c; - INEXACT REAL abig; - REAL ahi, alo, bhi, blo; - REAL err1, err2, err3; - - Split(b, bhi, blo); - Two_Product_Presplit(e[0], b, bhi, blo, Q, h[0]); - hindex = 1; - for (eindex = 1; eindex < elen; eindex++) { - enow = e[eindex]; - Two_Product_Presplit(enow, b, bhi, blo, product1, product0); - Two_Sum(Q, product0, sum, h[hindex]); - hindex++; - Two_Sum(product1, sum, Q, h[hindex]); - hindex++; - } - h[hindex] = Q; - return elen + elen; -} - -/*****************************************************************************/ -/* */ -/* scale_expansion_zeroelim() Multiply an expansion by a scalar, */ -/* eliminating zero components from the */ -/* output expansion. */ -/* */ -/* Sets h = be. See either version of my paper for details. */ -/* */ -/* Maintains the nonoverlapping property. If round-to-even is used (as */ -/* with IEEE 754), maintains the strongly nonoverlapping and nonadjacent */ -/* properties as well. (That is, if e has one of these properties, so */ -/* will h.) */ -/* */ -/*****************************************************************************/ - -int scale_expansion_zeroelim(elen, e, b, h) /* e and h cannot be the same. */ - int elen; - REAL *e; - REAL b; - REAL *h; -{ - INEXACT REAL Q, sum; - REAL hh; - INEXACT REAL product1; - REAL product0; - int eindex, hindex; - REAL enow; - INEXACT REAL bvirt; - REAL avirt, bround, around; - INEXACT REAL c; - INEXACT REAL abig; - REAL ahi, alo, bhi, blo; - REAL err1, err2, err3; - - Split(b, bhi, blo); - Two_Product_Presplit(e[0], b, bhi, blo, Q, hh); - hindex = 0; - if (hh != 0) { - h[hindex++] = hh; - } - for (eindex = 1; eindex < elen; eindex++) { - enow = e[eindex]; - Two_Product_Presplit(enow, b, bhi, blo, product1, product0); - Two_Sum(Q, product0, sum, hh); - if (hh != 0) { - h[hindex++] = hh; - } - Fast_Two_Sum(product1, sum, Q, hh); - if (hh != 0) { - h[hindex++] = hh; - } - } - if ((Q != 0.0) || (hindex == 0)) { - h[hindex++] = Q; - } - return hindex; -} - -/*****************************************************************************/ -/* */ -/* compress() Compress an expansion. */ -/* */ -/* See the long version of my paper for details. */ -/* */ -/* Maintains the nonoverlapping property. If round-to-even is used (as */ -/* with IEEE 754), then any nonoverlapping expansion is converted to a */ -/* nonadjacent expansion. */ -/* */ -/*****************************************************************************/ - -int compress(elen, e, h) /* e and h may be the same. */ - int elen; - REAL *e; - REAL *h; -{ - REAL Q, q; - INEXACT REAL Qnew; - int eindex, hindex; - INEXACT REAL bvirt; - REAL enow, hnow; - int top, bottom; - - bottom = elen - 1; - Q = e[bottom]; - for (eindex = elen - 2; eindex >= 0; eindex--) { - enow = e[eindex]; - Fast_Two_Sum(Q, enow, Qnew, q); - if (q != 0) { - h[bottom--] = Qnew; - Q = q; - } else { - Q = Qnew; - } - } - top = 0; - for (hindex = bottom + 1; hindex < elen; hindex++) { - hnow = h[hindex]; - Fast_Two_Sum(hnow, Q, Qnew, q); - if (q != 0) { - h[top++] = q; - } - Q = Qnew; - } - h[top] = Q; - return top + 1; -} - -/*****************************************************************************/ -/* */ -/* estimate() Produce a one-word estimate of an expansion's value. */ -/* */ -/* See either version of my paper for details. */ -/* */ -/*****************************************************************************/ - -REAL estimate(elen, e) - int elen; - REAL *e; -{ - REAL Q; - int eindex; - - Q = e[0]; - for (eindex = 1; eindex < elen; eindex++) { - Q += e[eindex]; - } - return Q; -} - -/*****************************************************************************/ -/* */ -/* orient2dfast() Approximate 2D orientation test. Nonrobust. */ -/* orient2dexact() Exact 2D orientation test. Robust. */ -/* orient2dslow() Another exact 2D orientation test. Robust. */ -/* orient2d() Adaptive exact 2D orientation test. Robust. */ -/* */ -/* Return a positive value if the points pa, pb, and pc occur */ -/* in counterclockwise order; a negative value if they occur */ -/* in clockwise order; and zero if they are collinear. The */ -/* result is also a rough approximation of twice the signed */ -/* area of the triangle defined by the three points. */ -/* */ -/* Only the first and last routine should be used; the middle two are for */ -/* timings. */ -/* */ -/* The last three use exact arithmetic to ensure a correct answer. The */ -/* result returned is the determinant of a matrix. In orient2d() only, */ -/* this determinant is computed adaptively, in the sense that exact */ -/* arithmetic is used only to the degree it is needed to ensure that the */ -/* returned value has the correct sign. Hence, orient2d() is usually quite */ -/* fast, but will run more slowly when the input points are collinear or */ -/* nearly so. */ -/* */ -/*****************************************************************************/ - -REAL orient2dfast(pa, pb, pc) - REAL *pa; - REAL *pb; - REAL *pc; -{ - REAL acx, bcx, acy, bcy; - - acx = pa[0] - pc[0]; - bcx = pb[0] - pc[0]; - acy = pa[1] - pc[1]; - bcy = pb[1] - pc[1]; - return acx * bcy - acy * bcx; -} - -REAL orient2dexact(pa, pb, pc) - REAL *pa; - REAL *pb; - REAL *pc; -{ - INEXACT REAL axby1, axcy1, bxcy1, bxay1, cxay1, cxby1; - REAL axby0, axcy0, bxcy0, bxay0, cxay0, cxby0; - REAL aterms[4], bterms[4], cterms[4]; - INEXACT REAL aterms3, bterms3, cterms3; - REAL v[8], w[12]; - int vlength, wlength; - - INEXACT REAL bvirt; - REAL avirt, bround, around; - INEXACT REAL c; - INEXACT REAL abig; - REAL ahi, alo, bhi, blo; - REAL err1, err2, err3; - INEXACT REAL _i, _j; - REAL _0; - - Two_Product(pa[0], pb[1], axby1, axby0); - Two_Product(pa[0], pc[1], axcy1, axcy0); - Two_Two_Diff(axby1, axby0, axcy1, axcy0, - aterms3, aterms[2], aterms[1], aterms[0]); - aterms[3] = aterms3; - - Two_Product(pb[0], pc[1], bxcy1, bxcy0); - Two_Product(pb[0], pa[1], bxay1, bxay0); - Two_Two_Diff(bxcy1, bxcy0, bxay1, bxay0, - bterms3, bterms[2], bterms[1], bterms[0]); - bterms[3] = bterms3; - - Two_Product(pc[0], pa[1], cxay1, cxay0); - Two_Product(pc[0], pb[1], cxby1, cxby0); - Two_Two_Diff(cxay1, cxay0, cxby1, cxby0, - cterms3, cterms[2], cterms[1], cterms[0]); - cterms[3] = cterms3; - - vlength = fast_expansion_sum_zeroelim(4, aterms, 4, bterms, v); - wlength = fast_expansion_sum_zeroelim(vlength, v, 4, cterms, w); - - return w[wlength - 1]; -} - -REAL orient2dslow(pa, pb, pc) - REAL *pa; - REAL *pb; - REAL *pc; -{ - INEXACT REAL acx, acy, bcx, bcy; - REAL acxtail, acytail; - REAL bcxtail, bcytail; - REAL negate, negatetail; - REAL axby[8], bxay[8]; - INEXACT REAL axby7, bxay7; - REAL deter[16]; - int deterlen; - - INEXACT REAL bvirt; - REAL avirt, bround, around; - INEXACT REAL c; - INEXACT REAL abig; - REAL a0hi, a0lo, a1hi, a1lo, bhi, blo; - REAL err1, err2, err3; - INEXACT REAL _i, _j, _k, _l, _m, _n; - REAL _0, _1, _2; - - Two_Diff(pa[0], pc[0], acx, acxtail); - Two_Diff(pa[1], pc[1], acy, acytail); - Two_Diff(pb[0], pc[0], bcx, bcxtail); - Two_Diff(pb[1], pc[1], bcy, bcytail); - - Two_Two_Product(acx, acxtail, bcy, bcytail, - axby7, axby[6], axby[5], axby[4], - axby[3], axby[2], axby[1], axby[0]); - axby[7] = axby7; - negate = -acy; - negatetail = -acytail; - Two_Two_Product(bcx, bcxtail, negate, negatetail, - bxay7, bxay[6], bxay[5], bxay[4], - bxay[3], bxay[2], bxay[1], bxay[0]); - bxay[7] = bxay7; - - deterlen = fast_expansion_sum_zeroelim(8, axby, 8, bxay, deter); - - return deter[deterlen - 1]; -} - -REAL orient2dadapt(pa, pb, pc, detsum) - REAL *pa; - REAL *pb; - REAL *pc; - REAL detsum; -{ - INEXACT REAL acx, acy, bcx, bcy; - REAL acxtail, acytail, bcxtail, bcytail; - INEXACT REAL detleft, detright; - REAL detlefttail, detrighttail; - REAL det, errbound; - REAL B[4], C1[8], C2[12], D[16]; - INEXACT REAL B3; - int C1length, C2length, Dlength; - REAL u[4]; - INEXACT REAL u3; - INEXACT REAL s1, t1; - REAL s0, t0; - - INEXACT REAL bvirt; - REAL avirt, bround, around; - INEXACT REAL c; - INEXACT REAL abig; - REAL ahi, alo, bhi, blo; - REAL err1, err2, err3; - INEXACT REAL _i, _j; - REAL _0; - - acx = (REAL) (pa[0] - pc[0]); - bcx = (REAL) (pb[0] - pc[0]); - acy = (REAL) (pa[1] - pc[1]); - bcy = (REAL) (pb[1] - pc[1]); - - Two_Product(acx, bcy, detleft, detlefttail); - Two_Product(acy, bcx, detright, detrighttail); - - Two_Two_Diff(detleft, detlefttail, detright, detrighttail, - B3, B[2], B[1], B[0]); - B[3] = B3; - - det = estimate(4, B); - errbound = ccwerrboundB * detsum; - if ((det >= errbound) || (-det >= errbound)) { - return det; - } - - Two_Diff_Tail(pa[0], pc[0], acx, acxtail); - Two_Diff_Tail(pb[0], pc[0], bcx, bcxtail); - Two_Diff_Tail(pa[1], pc[1], acy, acytail); - Two_Diff_Tail(pb[1], pc[1], bcy, bcytail); - - if ((acxtail == 0.0) && (acytail == 0.0) - && (bcxtail == 0.0) && (bcytail == 0.0)) { - return det; - } - - errbound = ccwerrboundC * detsum + resulterrbound * Absolute(det); - det += (acx * bcytail + bcy * acxtail) - - (acy * bcxtail + bcx * acytail); - if ((det >= errbound) || (-det >= errbound)) { - return det; - } - - Two_Product(acxtail, bcy, s1, s0); - Two_Product(acytail, bcx, t1, t0); - Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]); - u[3] = u3; - C1length = fast_expansion_sum_zeroelim(4, B, 4, u, C1); - - Two_Product(acx, bcytail, s1, s0); - Two_Product(acy, bcxtail, t1, t0); - Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]); - u[3] = u3; - C2length = fast_expansion_sum_zeroelim(C1length, C1, 4, u, C2); - - Two_Product(acxtail, bcytail, s1, s0); - Two_Product(acytail, bcxtail, t1, t0); - Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]); - u[3] = u3; - Dlength = fast_expansion_sum_zeroelim(C2length, C2, 4, u, D); - - return(D[Dlength - 1]); -} - -REAL orient2d(pa, pb, pc) - REAL *pa; - REAL *pb; - REAL *pc; -{ - REAL detleft, detright, det; - REAL detsum, errbound; - - detleft = (pa[0] - pc[0]) * (pb[1] - pc[1]); - detright = (pa[1] - pc[1]) * (pb[0] - pc[0]); - det = detleft - detright; - - if (detleft > 0.0) { - if (detright <= 0.0) { - return det; - } else { - detsum = detleft + detright; - } - } else if (detleft < 0.0) { - if (detright >= 0.0) { - return det; - } else { - detsum = -detleft - detright; - } - } else { - return det; - } - - errbound = ccwerrboundA * detsum; - if ((det >= errbound) || (-det >= errbound)) { - return det; - } - - return orient2dadapt(pa, pb, pc, detsum); -} - -/*****************************************************************************/ -/* */ -/* orient3dfast() Approximate 3D orientation test. Nonrobust. */ -/* orient3dexact() Exact 3D orientation test. Robust. */ -/* orient3dslow() Another exact 3D orientation test. Robust. */ -/* orient3d() Adaptive exact 3D orientation test. Robust. */ -/* */ -/* Return a positive value if the point pd lies below the */ -/* plane passing through pa, pb, and pc; "below" is defined so */ -/* that pa, pb, and pc appear in counterclockwise order when */ -/* viewed from above the plane. Returns a negative value if */ -/* pd lies above the plane. Returns zero if the points are */ -/* coplanar. The result is also a rough approximation of six */ -/* times the signed volume of the tetrahedron defined by the */ -/* four points. */ -/* */ -/* Only the first and last routine should be used; the middle two are for */ -/* timings. */ -/* */ -/* The last three use exact arithmetic to ensure a correct answer. The */ -/* result returned is the determinant of a matrix. In orient3d() only, */ -/* this determinant is computed adaptively, in the sense that exact */ -/* arithmetic is used only to the degree it is needed to ensure that the */ -/* returned value has the correct sign. Hence, orient3d() is usually quite */ -/* fast, but will run more slowly when the input points are coplanar or */ -/* nearly so. */ -/* */ -/*****************************************************************************/ - -REAL orient3dfast(pa, pb, pc, pd) - REAL *pa; - REAL *pb; - REAL *pc; - REAL *pd; -{ - REAL adx, bdx, cdx; - REAL ady, bdy, cdy; - REAL adz, bdz, cdz; - - adx = pa[0] - pd[0]; - bdx = pb[0] - pd[0]; - cdx = pc[0] - pd[0]; - ady = pa[1] - pd[1]; - bdy = pb[1] - pd[1]; - cdy = pc[1] - pd[1]; - adz = pa[2] - pd[2]; - bdz = pb[2] - pd[2]; - cdz = pc[2] - pd[2]; - - return adx * (bdy * cdz - bdz * cdy) - + bdx * (cdy * adz - cdz * ady) - + cdx * (ady * bdz - adz * bdy); -} - -REAL orient3dexact(pa, pb, pc, pd) - REAL *pa; - REAL *pb; - REAL *pc; - REAL *pd; -{ - INEXACT REAL axby1, bxcy1, cxdy1, dxay1, axcy1, bxdy1; - INEXACT REAL bxay1, cxby1, dxcy1, axdy1, cxay1, dxby1; - REAL axby0, bxcy0, cxdy0, dxay0, axcy0, bxdy0; - REAL bxay0, cxby0, dxcy0, axdy0, cxay0, dxby0; - REAL ab[4], bc[4], cd[4], da[4], ac[4], bd[4]; - REAL temp8[8]; - int templen; - REAL abc[12], bcd[12], cda[12], dab[12]; - int abclen, bcdlen, cdalen, dablen; - REAL adet[24], bdet[24], cdet[24], ddet[24]; - int alen, blen, clen, dlen; - REAL abdet[48], cddet[48]; - int ablen, cdlen; - REAL deter[96]; - int deterlen; - int i; - - INEXACT REAL bvirt; - REAL avirt, bround, around; - INEXACT REAL c; - INEXACT REAL abig; - REAL ahi, alo, bhi, blo; - REAL err1, err2, err3; - INEXACT REAL _i, _j; - REAL _0; - - Two_Product(pa[0], pb[1], axby1, axby0); - Two_Product(pb[0], pa[1], bxay1, bxay0); - Two_Two_Diff(axby1, axby0, bxay1, bxay0, ab[3], ab[2], ab[1], ab[0]); - - Two_Product(pb[0], pc[1], bxcy1, bxcy0); - Two_Product(pc[0], pb[1], cxby1, cxby0); - Two_Two_Diff(bxcy1, bxcy0, cxby1, cxby0, bc[3], bc[2], bc[1], bc[0]); - - Two_Product(pc[0], pd[1], cxdy1, cxdy0); - Two_Product(pd[0], pc[1], dxcy1, dxcy0); - Two_Two_Diff(cxdy1, cxdy0, dxcy1, dxcy0, cd[3], cd[2], cd[1], cd[0]); - - Two_Product(pd[0], pa[1], dxay1, dxay0); - Two_Product(pa[0], pd[1], axdy1, axdy0); - Two_Two_Diff(dxay1, dxay0, axdy1, axdy0, da[3], da[2], da[1], da[0]); - - Two_Product(pa[0], pc[1], axcy1, axcy0); - Two_Product(pc[0], pa[1], cxay1, cxay0); - Two_Two_Diff(axcy1, axcy0, cxay1, cxay0, ac[3], ac[2], ac[1], ac[0]); - - Two_Product(pb[0], pd[1], bxdy1, bxdy0); - Two_Product(pd[0], pb[1], dxby1, dxby0); - Two_Two_Diff(bxdy1, bxdy0, dxby1, dxby0, bd[3], bd[2], bd[1], bd[0]); - - templen = fast_expansion_sum_zeroelim(4, cd, 4, da, temp8); - cdalen = fast_expansion_sum_zeroelim(templen, temp8, 4, ac, cda); - templen = fast_expansion_sum_zeroelim(4, da, 4, ab, temp8); - dablen = fast_expansion_sum_zeroelim(templen, temp8, 4, bd, dab); - for (i = 0; i < 4; i++) { - bd[i] = -bd[i]; - ac[i] = -ac[i]; - } - templen = fast_expansion_sum_zeroelim(4, ab, 4, bc, temp8); - abclen = fast_expansion_sum_zeroelim(templen, temp8, 4, ac, abc); - templen = fast_expansion_sum_zeroelim(4, bc, 4, cd, temp8); - bcdlen = fast_expansion_sum_zeroelim(templen, temp8, 4, bd, bcd); - - alen = scale_expansion_zeroelim(bcdlen, bcd, pa[2], adet); - blen = scale_expansion_zeroelim(cdalen, cda, -pb[2], bdet); - clen = scale_expansion_zeroelim(dablen, dab, pc[2], cdet); - dlen = scale_expansion_zeroelim(abclen, abc, -pd[2], ddet); - - ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet); - cdlen = fast_expansion_sum_zeroelim(clen, cdet, dlen, ddet, cddet); - deterlen = fast_expansion_sum_zeroelim(ablen, abdet, cdlen, cddet, deter); - - return deter[deterlen - 1]; -} - -REAL orient3dslow(pa, pb, pc, pd) - REAL *pa; - REAL *pb; - REAL *pc; - REAL *pd; -{ - INEXACT REAL adx, ady, adz, bdx, bdy, bdz, cdx, cdy, cdz; - REAL adxtail, adytail, adztail; - REAL bdxtail, bdytail, bdztail; - REAL cdxtail, cdytail, cdztail; - REAL negate, negatetail; - INEXACT REAL axby7, bxcy7, axcy7, bxay7, cxby7, cxay7; - REAL axby[8], bxcy[8], axcy[8], bxay[8], cxby[8], cxay[8]; - REAL temp16[16], temp32[32], temp32t[32]; - int temp16len, temp32len, temp32tlen; - REAL adet[64], bdet[64], cdet[64]; - int alen, blen, clen; - REAL abdet[128]; - int ablen; - REAL deter[192]; - int deterlen; - - INEXACT REAL bvirt; - REAL avirt, bround, around; - INEXACT REAL c; - INEXACT REAL abig; - REAL a0hi, a0lo, a1hi, a1lo, bhi, blo; - REAL err1, err2, err3; - INEXACT REAL _i, _j, _k, _l, _m, _n; - REAL _0, _1, _2; - - Two_Diff(pa[0], pd[0], adx, adxtail); - Two_Diff(pa[1], pd[1], ady, adytail); - Two_Diff(pa[2], pd[2], adz, adztail); - Two_Diff(pb[0], pd[0], bdx, bdxtail); - Two_Diff(pb[1], pd[1], bdy, bdytail); - Two_Diff(pb[2], pd[2], bdz, bdztail); - Two_Diff(pc[0], pd[0], cdx, cdxtail); - Two_Diff(pc[1], pd[1], cdy, cdytail); - Two_Diff(pc[2], pd[2], cdz, cdztail); - - Two_Two_Product(adx, adxtail, bdy, bdytail, - axby7, axby[6], axby[5], axby[4], - axby[3], axby[2], axby[1], axby[0]); - axby[7] = axby7; - negate = -ady; - negatetail = -adytail; - Two_Two_Product(bdx, bdxtail, negate, negatetail, - bxay7, bxay[6], bxay[5], bxay[4], - bxay[3], bxay[2], bxay[1], bxay[0]); - bxay[7] = bxay7; - Two_Two_Product(bdx, bdxtail, cdy, cdytail, - bxcy7, bxcy[6], bxcy[5], bxcy[4], - bxcy[3], bxcy[2], bxcy[1], bxcy[0]); - bxcy[7] = bxcy7; - negate = -bdy; - negatetail = -bdytail; - Two_Two_Product(cdx, cdxtail, negate, negatetail, - cxby7, cxby[6], cxby[5], cxby[4], - cxby[3], cxby[2], cxby[1], cxby[0]); - cxby[7] = cxby7; - Two_Two_Product(cdx, cdxtail, ady, adytail, - cxay7, cxay[6], cxay[5], cxay[4], - cxay[3], cxay[2], cxay[1], cxay[0]); - cxay[7] = cxay7; - negate = -cdy; - negatetail = -cdytail; - Two_Two_Product(adx, adxtail, negate, negatetail, - axcy7, axcy[6], axcy[5], axcy[4], - axcy[3], axcy[2], axcy[1], axcy[0]); - axcy[7] = axcy7; - - temp16len = fast_expansion_sum_zeroelim(8, bxcy, 8, cxby, temp16); - temp32len = scale_expansion_zeroelim(temp16len, temp16, adz, temp32); - temp32tlen = scale_expansion_zeroelim(temp16len, temp16, adztail, temp32t); - alen = fast_expansion_sum_zeroelim(temp32len, temp32, temp32tlen, temp32t, - adet); - - temp16len = fast_expansion_sum_zeroelim(8, cxay, 8, axcy, temp16); - temp32len = scale_expansion_zeroelim(temp16len, temp16, bdz, temp32); - temp32tlen = scale_expansion_zeroelim(temp16len, temp16, bdztail, temp32t); - blen = fast_expansion_sum_zeroelim(temp32len, temp32, temp32tlen, temp32t, - bdet); - - temp16len = fast_expansion_sum_zeroelim(8, axby, 8, bxay, temp16); - temp32len = scale_expansion_zeroelim(temp16len, temp16, cdz, temp32); - temp32tlen = scale_expansion_zeroelim(temp16len, temp16, cdztail, temp32t); - clen = fast_expansion_sum_zeroelim(temp32len, temp32, temp32tlen, temp32t, - cdet); - - ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet); - deterlen = fast_expansion_sum_zeroelim(ablen, abdet, clen, cdet, deter); - - return deter[deterlen - 1]; -} - -REAL orient3dadapt(pa, pb, pc, pd, permanent) - REAL *pa; - REAL *pb; - REAL *pc; - REAL *pd; - REAL permanent; -{ - INEXACT REAL adx, bdx, cdx, ady, bdy, cdy, adz, bdz, cdz; - REAL det, errbound; - - INEXACT REAL bdxcdy1, cdxbdy1, cdxady1, adxcdy1, adxbdy1, bdxady1; - REAL bdxcdy0, cdxbdy0, cdxady0, adxcdy0, adxbdy0, bdxady0; - REAL bc[4], ca[4], ab[4]; - INEXACT REAL bc3, ca3, ab3; - REAL adet[8], bdet[8], cdet[8]; - int alen, blen, clen; - REAL abdet[16]; - int ablen; - REAL *finnow, *finother, *finswap; - REAL fin1[192], fin2[192]; - int finlength; - - REAL adxtail, bdxtail, cdxtail; - REAL adytail, bdytail, cdytail; - REAL adztail, bdztail, cdztail; - INEXACT REAL at_blarge, at_clarge; - INEXACT REAL bt_clarge, bt_alarge; - INEXACT REAL ct_alarge, ct_blarge; - REAL at_b[4], at_c[4], bt_c[4], bt_a[4], ct_a[4], ct_b[4]; - int at_blen, at_clen, bt_clen, bt_alen, ct_alen, ct_blen; - INEXACT REAL bdxt_cdy1, cdxt_bdy1, cdxt_ady1; - INEXACT REAL adxt_cdy1, adxt_bdy1, bdxt_ady1; - REAL bdxt_cdy0, cdxt_bdy0, cdxt_ady0; - REAL adxt_cdy0, adxt_bdy0, bdxt_ady0; - INEXACT REAL bdyt_cdx1, cdyt_bdx1, cdyt_adx1; - INEXACT REAL adyt_cdx1, adyt_bdx1, bdyt_adx1; - REAL bdyt_cdx0, cdyt_bdx0, cdyt_adx0; - REAL adyt_cdx0, adyt_bdx0, bdyt_adx0; - REAL bct[8], cat[8], abt[8]; - int bctlen, catlen, abtlen; - INEXACT REAL bdxt_cdyt1, cdxt_bdyt1, cdxt_adyt1; - INEXACT REAL adxt_cdyt1, adxt_bdyt1, bdxt_adyt1; - REAL bdxt_cdyt0, cdxt_bdyt0, cdxt_adyt0; - REAL adxt_cdyt0, adxt_bdyt0, bdxt_adyt0; - REAL u[4], v[12], w[16]; - INEXACT REAL u3; - int vlength, wlength; - REAL negate; - - INEXACT REAL bvirt; - REAL avirt, bround, around; - INEXACT REAL c; - INEXACT REAL abig; - REAL ahi, alo, bhi, blo; - REAL err1, err2, err3; - INEXACT REAL _i, _j, _k; - REAL _0; - - adx = (REAL) (pa[0] - pd[0]); - bdx = (REAL) (pb[0] - pd[0]); - cdx = (REAL) (pc[0] - pd[0]); - ady = (REAL) (pa[1] - pd[1]); - bdy = (REAL) (pb[1] - pd[1]); - cdy = (REAL) (pc[1] - pd[1]); - adz = (REAL) (pa[2] - pd[2]); - bdz = (REAL) (pb[2] - pd[2]); - cdz = (REAL) (pc[2] - pd[2]); - - Two_Product(bdx, cdy, bdxcdy1, bdxcdy0); - Two_Product(cdx, bdy, cdxbdy1, cdxbdy0); - Two_Two_Diff(bdxcdy1, bdxcdy0, cdxbdy1, cdxbdy0, bc3, bc[2], bc[1], bc[0]); - bc[3] = bc3; - alen = scale_expansion_zeroelim(4, bc, adz, adet); - - Two_Product(cdx, ady, cdxady1, cdxady0); - Two_Product(adx, cdy, adxcdy1, adxcdy0); - Two_Two_Diff(cdxady1, cdxady0, adxcdy1, adxcdy0, ca3, ca[2], ca[1], ca[0]); - ca[3] = ca3; - blen = scale_expansion_zeroelim(4, ca, bdz, bdet); - - Two_Product(adx, bdy, adxbdy1, adxbdy0); - Two_Product(bdx, ady, bdxady1, bdxady0); - Two_Two_Diff(adxbdy1, adxbdy0, bdxady1, bdxady0, ab3, ab[2], ab[1], ab[0]); - ab[3] = ab3; - clen = scale_expansion_zeroelim(4, ab, cdz, cdet); - - ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet); - finlength = fast_expansion_sum_zeroelim(ablen, abdet, clen, cdet, fin1); - - det = estimate(finlength, fin1); - errbound = o3derrboundB * permanent; - if ((det >= errbound) || (-det >= errbound)) { - return det; - } - - Two_Diff_Tail(pa[0], pd[0], adx, adxtail); - Two_Diff_Tail(pb[0], pd[0], bdx, bdxtail); - Two_Diff_Tail(pc[0], pd[0], cdx, cdxtail); - Two_Diff_Tail(pa[1], pd[1], ady, adytail); - Two_Diff_Tail(pb[1], pd[1], bdy, bdytail); - Two_Diff_Tail(pc[1], pd[1], cdy, cdytail); - Two_Diff_Tail(pa[2], pd[2], adz, adztail); - Two_Diff_Tail(pb[2], pd[2], bdz, bdztail); - Two_Diff_Tail(pc[2], pd[2], cdz, cdztail); - - if ((adxtail == 0.0) && (bdxtail == 0.0) && (cdxtail == 0.0) - && (adytail == 0.0) && (bdytail == 0.0) && (cdytail == 0.0) - && (adztail == 0.0) && (bdztail == 0.0) && (cdztail == 0.0)) { - return det; - } - - errbound = o3derrboundC * permanent + resulterrbound * Absolute(det); - det += (adz * ((bdx * cdytail + cdy * bdxtail) - - (bdy * cdxtail + cdx * bdytail)) - + adztail * (bdx * cdy - bdy * cdx)) - + (bdz * ((cdx * adytail + ady * cdxtail) - - (cdy * adxtail + adx * cdytail)) - + bdztail * (cdx * ady - cdy * adx)) - + (cdz * ((adx * bdytail + bdy * adxtail) - - (ady * bdxtail + bdx * adytail)) - + cdztail * (adx * bdy - ady * bdx)); - if ((det >= errbound) || (-det >= errbound)) { - return det; - } - - finnow = fin1; - finother = fin2; - - if (adxtail == 0.0) { - if (adytail == 0.0) { - at_b[0] = 0.0; - at_blen = 1; - at_c[0] = 0.0; - at_clen = 1; - } else { - negate = -adytail; - Two_Product(negate, bdx, at_blarge, at_b[0]); - at_b[1] = at_blarge; - at_blen = 2; - Two_Product(adytail, cdx, at_clarge, at_c[0]); - at_c[1] = at_clarge; - at_clen = 2; - } - } else { - if (adytail == 0.0) { - Two_Product(adxtail, bdy, at_blarge, at_b[0]); - at_b[1] = at_blarge; - at_blen = 2; - negate = -adxtail; - Two_Product(negate, cdy, at_clarge, at_c[0]); - at_c[1] = at_clarge; - at_clen = 2; - } else { - Two_Product(adxtail, bdy, adxt_bdy1, adxt_bdy0); - Two_Product(adytail, bdx, adyt_bdx1, adyt_bdx0); - Two_Two_Diff(adxt_bdy1, adxt_bdy0, adyt_bdx1, adyt_bdx0, - at_blarge, at_b[2], at_b[1], at_b[0]); - at_b[3] = at_blarge; - at_blen = 4; - Two_Product(adytail, cdx, adyt_cdx1, adyt_cdx0); - Two_Product(adxtail, cdy, adxt_cdy1, adxt_cdy0); - Two_Two_Diff(adyt_cdx1, adyt_cdx0, adxt_cdy1, adxt_cdy0, - at_clarge, at_c[2], at_c[1], at_c[0]); - at_c[3] = at_clarge; - at_clen = 4; - } - } - if (bdxtail == 0.0) { - if (bdytail == 0.0) { - bt_c[0] = 0.0; - bt_clen = 1; - bt_a[0] = 0.0; - bt_alen = 1; - } else { - negate = -bdytail; - Two_Product(negate, cdx, bt_clarge, bt_c[0]); - bt_c[1] = bt_clarge; - bt_clen = 2; - Two_Product(bdytail, adx, bt_alarge, bt_a[0]); - bt_a[1] = bt_alarge; - bt_alen = 2; - } - } else { - if (bdytail == 0.0) { - Two_Product(bdxtail, cdy, bt_clarge, bt_c[0]); - bt_c[1] = bt_clarge; - bt_clen = 2; - negate = -bdxtail; - Two_Product(negate, ady, bt_alarge, bt_a[0]); - bt_a[1] = bt_alarge; - bt_alen = 2; - } else { - Two_Product(bdxtail, cdy, bdxt_cdy1, bdxt_cdy0); - Two_Product(bdytail, cdx, bdyt_cdx1, bdyt_cdx0); - Two_Two_Diff(bdxt_cdy1, bdxt_cdy0, bdyt_cdx1, bdyt_cdx0, - bt_clarge, bt_c[2], bt_c[1], bt_c[0]); - bt_c[3] = bt_clarge; - bt_clen = 4; - Two_Product(bdytail, adx, bdyt_adx1, bdyt_adx0); - Two_Product(bdxtail, ady, bdxt_ady1, bdxt_ady0); - Two_Two_Diff(bdyt_adx1, bdyt_adx0, bdxt_ady1, bdxt_ady0, - bt_alarge, bt_a[2], bt_a[1], bt_a[0]); - bt_a[3] = bt_alarge; - bt_alen = 4; - } - } - if (cdxtail == 0.0) { - if (cdytail == 0.0) { - ct_a[0] = 0.0; - ct_alen = 1; - ct_b[0] = 0.0; - ct_blen = 1; - } else { - negate = -cdytail; - Two_Product(negate, adx, ct_alarge, ct_a[0]); - ct_a[1] = ct_alarge; - ct_alen = 2; - Two_Product(cdytail, bdx, ct_blarge, ct_b[0]); - ct_b[1] = ct_blarge; - ct_blen = 2; - } - } else { - if (cdytail == 0.0) { - Two_Product(cdxtail, ady, ct_alarge, ct_a[0]); - ct_a[1] = ct_alarge; - ct_alen = 2; - negate = -cdxtail; - Two_Product(negate, bdy, ct_blarge, ct_b[0]); - ct_b[1] = ct_blarge; - ct_blen = 2; - } else { - Two_Product(cdxtail, ady, cdxt_ady1, cdxt_ady0); - Two_Product(cdytail, adx, cdyt_adx1, cdyt_adx0); - Two_Two_Diff(cdxt_ady1, cdxt_ady0, cdyt_adx1, cdyt_adx0, - ct_alarge, ct_a[2], ct_a[1], ct_a[0]); - ct_a[3] = ct_alarge; - ct_alen = 4; - Two_Product(cdytail, bdx, cdyt_bdx1, cdyt_bdx0); - Two_Product(cdxtail, bdy, cdxt_bdy1, cdxt_bdy0); - Two_Two_Diff(cdyt_bdx1, cdyt_bdx0, cdxt_bdy1, cdxt_bdy0, - ct_blarge, ct_b[2], ct_b[1], ct_b[0]); - ct_b[3] = ct_blarge; - ct_blen = 4; - } - } - - bctlen = fast_expansion_sum_zeroelim(bt_clen, bt_c, ct_blen, ct_b, bct); - wlength = scale_expansion_zeroelim(bctlen, bct, adz, w); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, - finother); - finswap = finnow; finnow = finother; finother = finswap; - - catlen = fast_expansion_sum_zeroelim(ct_alen, ct_a, at_clen, at_c, cat); - wlength = scale_expansion_zeroelim(catlen, cat, bdz, w); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, - finother); - finswap = finnow; finnow = finother; finother = finswap; - - abtlen = fast_expansion_sum_zeroelim(at_blen, at_b, bt_alen, bt_a, abt); - wlength = scale_expansion_zeroelim(abtlen, abt, cdz, w); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, - finother); - finswap = finnow; finnow = finother; finother = finswap; - - if (adztail != 0.0) { - vlength = scale_expansion_zeroelim(4, bc, adztail, v); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, vlength, v, - finother); - finswap = finnow; finnow = finother; finother = finswap; - } - if (bdztail != 0.0) { - vlength = scale_expansion_zeroelim(4, ca, bdztail, v); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, vlength, v, - finother); - finswap = finnow; finnow = finother; finother = finswap; - } - if (cdztail != 0.0) { - vlength = scale_expansion_zeroelim(4, ab, cdztail, v); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, vlength, v, - finother); - finswap = finnow; finnow = finother; finother = finswap; - } - - if (adxtail != 0.0) { - if (bdytail != 0.0) { - Two_Product(adxtail, bdytail, adxt_bdyt1, adxt_bdyt0); - Two_One_Product(adxt_bdyt1, adxt_bdyt0, cdz, u3, u[2], u[1], u[0]); - u[3] = u3; - finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, - finother); - finswap = finnow; finnow = finother; finother = finswap; - if (cdztail != 0.0) { - Two_One_Product(adxt_bdyt1, adxt_bdyt0, cdztail, u3, u[2], u[1], u[0]); - u[3] = u3; - finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, - finother); - finswap = finnow; finnow = finother; finother = finswap; - } - } - if (cdytail != 0.0) { - negate = -adxtail; - Two_Product(negate, cdytail, adxt_cdyt1, adxt_cdyt0); - Two_One_Product(adxt_cdyt1, adxt_cdyt0, bdz, u3, u[2], u[1], u[0]); - u[3] = u3; - finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, - finother); - finswap = finnow; finnow = finother; finother = finswap; - if (bdztail != 0.0) { - Two_One_Product(adxt_cdyt1, adxt_cdyt0, bdztail, u3, u[2], u[1], u[0]); - u[3] = u3; - finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, - finother); - finswap = finnow; finnow = finother; finother = finswap; - } - } - } - if (bdxtail != 0.0) { - if (cdytail != 0.0) { - Two_Product(bdxtail, cdytail, bdxt_cdyt1, bdxt_cdyt0); - Two_One_Product(bdxt_cdyt1, bdxt_cdyt0, adz, u3, u[2], u[1], u[0]); - u[3] = u3; - finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, - finother); - finswap = finnow; finnow = finother; finother = finswap; - if (adztail != 0.0) { - Two_One_Product(bdxt_cdyt1, bdxt_cdyt0, adztail, u3, u[2], u[1], u[0]); - u[3] = u3; - finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, - finother); - finswap = finnow; finnow = finother; finother = finswap; - } - } - if (adytail != 0.0) { - negate = -bdxtail; - Two_Product(negate, adytail, bdxt_adyt1, bdxt_adyt0); - Two_One_Product(bdxt_adyt1, bdxt_adyt0, cdz, u3, u[2], u[1], u[0]); - u[3] = u3; - finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, - finother); - finswap = finnow; finnow = finother; finother = finswap; - if (cdztail != 0.0) { - Two_One_Product(bdxt_adyt1, bdxt_adyt0, cdztail, u3, u[2], u[1], u[0]); - u[3] = u3; - finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, - finother); - finswap = finnow; finnow = finother; finother = finswap; - } - } - } - if (cdxtail != 0.0) { - if (adytail != 0.0) { - Two_Product(cdxtail, adytail, cdxt_adyt1, cdxt_adyt0); - Two_One_Product(cdxt_adyt1, cdxt_adyt0, bdz, u3, u[2], u[1], u[0]); - u[3] = u3; - finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, - finother); - finswap = finnow; finnow = finother; finother = finswap; - if (bdztail != 0.0) { - Two_One_Product(cdxt_adyt1, cdxt_adyt0, bdztail, u3, u[2], u[1], u[0]); - u[3] = u3; - finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, - finother); - finswap = finnow; finnow = finother; finother = finswap; - } - } - if (bdytail != 0.0) { - negate = -cdxtail; - Two_Product(negate, bdytail, cdxt_bdyt1, cdxt_bdyt0); - Two_One_Product(cdxt_bdyt1, cdxt_bdyt0, adz, u3, u[2], u[1], u[0]); - u[3] = u3; - finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, - finother); - finswap = finnow; finnow = finother; finother = finswap; - if (adztail != 0.0) { - Two_One_Product(cdxt_bdyt1, cdxt_bdyt0, adztail, u3, u[2], u[1], u[0]); - u[3] = u3; - finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, - finother); - finswap = finnow; finnow = finother; finother = finswap; - } - } - } - - if (adztail != 0.0) { - wlength = scale_expansion_zeroelim(bctlen, bct, adztail, w); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, - finother); - finswap = finnow; finnow = finother; finother = finswap; - } - if (bdztail != 0.0) { - wlength = scale_expansion_zeroelim(catlen, cat, bdztail, w); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, - finother); - finswap = finnow; finnow = finother; finother = finswap; - } - if (cdztail != 0.0) { - wlength = scale_expansion_zeroelim(abtlen, abt, cdztail, w); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, - finother); - finswap = finnow; finnow = finother; finother = finswap; - } - - return finnow[finlength - 1]; -} - -REAL orient3d(pa, pb, pc, pd) - REAL *pa; - REAL *pb; - REAL *pc; - REAL *pd; -{ - REAL adx, bdx, cdx, ady, bdy, cdy, adz, bdz, cdz; - REAL bdxcdy, cdxbdy, cdxady, adxcdy, adxbdy, bdxady; - REAL det; - REAL permanent, errbound; - - adx = pa[0] - pd[0]; - bdx = pb[0] - pd[0]; - cdx = pc[0] - pd[0]; - ady = pa[1] - pd[1]; - bdy = pb[1] - pd[1]; - cdy = pc[1] - pd[1]; - adz = pa[2] - pd[2]; - bdz = pb[2] - pd[2]; - cdz = pc[2] - pd[2]; - - bdxcdy = bdx * cdy; - cdxbdy = cdx * bdy; - - cdxady = cdx * ady; - adxcdy = adx * cdy; - - adxbdy = adx * bdy; - bdxady = bdx * ady; - - det = adz * (bdxcdy - cdxbdy) - + bdz * (cdxady - adxcdy) - + cdz * (adxbdy - bdxady); - - permanent = (Absolute(bdxcdy) + Absolute(cdxbdy)) * Absolute(adz) - + (Absolute(cdxady) + Absolute(adxcdy)) * Absolute(bdz) - + (Absolute(adxbdy) + Absolute(bdxady)) * Absolute(cdz); - errbound = o3derrboundA * permanent; - if ((det > errbound) || (-det > errbound)) { - return det; - } - - return orient3dadapt(pa, pb, pc, pd, permanent); -} - -/*****************************************************************************/ -/* */ -/* incirclefast() Approximate 2D incircle test. Nonrobust. */ -/* incircleexact() Exact 2D incircle test. Robust. */ -/* incircleslow() Another exact 2D incircle test. Robust. */ -/* incircle() Adaptive exact 2D incircle test. Robust. */ -/* */ -/* Return a positive value if the point pd lies inside the */ -/* circle passing through pa, pb, and pc; a negative value if */ -/* it lies outside; and zero if the four points are cocircular.*/ -/* The points pa, pb, and pc must be in counterclockwise */ -/* order, or the sign of the result will be reversed. */ -/* */ -/* Only the first and last routine should be used; the middle two are for */ -/* timings. */ -/* */ -/* The last three use exact arithmetic to ensure a correct answer. The */ -/* result returned is the determinant of a matrix. In incircle() only, */ -/* this determinant is computed adaptively, in the sense that exact */ -/* arithmetic is used only to the degree it is needed to ensure that the */ -/* returned value has the correct sign. Hence, incircle() is usually quite */ -/* fast, but will run more slowly when the input points are cocircular or */ -/* nearly so. */ -/* */ -/*****************************************************************************/ - -REAL incirclefast(pa, pb, pc, pd) - REAL *pa; - REAL *pb; - REAL *pc; - REAL *pd; -{ - REAL adx, ady, bdx, bdy, cdx, cdy; - REAL abdet, bcdet, cadet; - REAL alift, blift, clift; - - adx = pa[0] - pd[0]; - ady = pa[1] - pd[1]; - bdx = pb[0] - pd[0]; - bdy = pb[1] - pd[1]; - cdx = pc[0] - pd[0]; - cdy = pc[1] - pd[1]; - - abdet = adx * bdy - bdx * ady; - bcdet = bdx * cdy - cdx * bdy; - cadet = cdx * ady - adx * cdy; - alift = adx * adx + ady * ady; - blift = bdx * bdx + bdy * bdy; - clift = cdx * cdx + cdy * cdy; - - return alift * bcdet + blift * cadet + clift * abdet; -} - -REAL incircleexact(pa, pb, pc, pd) - REAL *pa; - REAL *pb; - REAL *pc; - REAL *pd; -{ - INEXACT REAL axby1, bxcy1, cxdy1, dxay1, axcy1, bxdy1; - INEXACT REAL bxay1, cxby1, dxcy1, axdy1, cxay1, dxby1; - REAL axby0, bxcy0, cxdy0, dxay0, axcy0, bxdy0; - REAL bxay0, cxby0, dxcy0, axdy0, cxay0, dxby0; - REAL ab[4], bc[4], cd[4], da[4], ac[4], bd[4]; - REAL temp8[8]; - int templen; - REAL abc[12], bcd[12], cda[12], dab[12]; - int abclen, bcdlen, cdalen, dablen; - REAL det24x[24], det24y[24], det48x[48], det48y[48]; - int xlen, ylen; - REAL adet[96], bdet[96], cdet[96], ddet[96]; - int alen, blen, clen, dlen; - REAL abdet[192], cddet[192]; - int ablen, cdlen; - REAL deter[384]; - int deterlen; - int i; - - INEXACT REAL bvirt; - REAL avirt, bround, around; - INEXACT REAL c; - INEXACT REAL abig; - REAL ahi, alo, bhi, blo; - REAL err1, err2, err3; - INEXACT REAL _i, _j; - REAL _0; - - Two_Product(pa[0], pb[1], axby1, axby0); - Two_Product(pb[0], pa[1], bxay1, bxay0); - Two_Two_Diff(axby1, axby0, bxay1, bxay0, ab[3], ab[2], ab[1], ab[0]); - - Two_Product(pb[0], pc[1], bxcy1, bxcy0); - Two_Product(pc[0], pb[1], cxby1, cxby0); - Two_Two_Diff(bxcy1, bxcy0, cxby1, cxby0, bc[3], bc[2], bc[1], bc[0]); - - Two_Product(pc[0], pd[1], cxdy1, cxdy0); - Two_Product(pd[0], pc[1], dxcy1, dxcy0); - Two_Two_Diff(cxdy1, cxdy0, dxcy1, dxcy0, cd[3], cd[2], cd[1], cd[0]); - - Two_Product(pd[0], pa[1], dxay1, dxay0); - Two_Product(pa[0], pd[1], axdy1, axdy0); - Two_Two_Diff(dxay1, dxay0, axdy1, axdy0, da[3], da[2], da[1], da[0]); - - Two_Product(pa[0], pc[1], axcy1, axcy0); - Two_Product(pc[0], pa[1], cxay1, cxay0); - Two_Two_Diff(axcy1, axcy0, cxay1, cxay0, ac[3], ac[2], ac[1], ac[0]); - - Two_Product(pb[0], pd[1], bxdy1, bxdy0); - Two_Product(pd[0], pb[1], dxby1, dxby0); - Two_Two_Diff(bxdy1, bxdy0, dxby1, dxby0, bd[3], bd[2], bd[1], bd[0]); - - templen = fast_expansion_sum_zeroelim(4, cd, 4, da, temp8); - cdalen = fast_expansion_sum_zeroelim(templen, temp8, 4, ac, cda); - templen = fast_expansion_sum_zeroelim(4, da, 4, ab, temp8); - dablen = fast_expansion_sum_zeroelim(templen, temp8, 4, bd, dab); - for (i = 0; i < 4; i++) { - bd[i] = -bd[i]; - ac[i] = -ac[i]; - } - templen = fast_expansion_sum_zeroelim(4, ab, 4, bc, temp8); - abclen = fast_expansion_sum_zeroelim(templen, temp8, 4, ac, abc); - templen = fast_expansion_sum_zeroelim(4, bc, 4, cd, temp8); - bcdlen = fast_expansion_sum_zeroelim(templen, temp8, 4, bd, bcd); - - xlen = scale_expansion_zeroelim(bcdlen, bcd, pa[0], det24x); - xlen = scale_expansion_zeroelim(xlen, det24x, pa[0], det48x); - ylen = scale_expansion_zeroelim(bcdlen, bcd, pa[1], det24y); - ylen = scale_expansion_zeroelim(ylen, det24y, pa[1], det48y); - alen = fast_expansion_sum_zeroelim(xlen, det48x, ylen, det48y, adet); - - xlen = scale_expansion_zeroelim(cdalen, cda, pb[0], det24x); - xlen = scale_expansion_zeroelim(xlen, det24x, -pb[0], det48x); - ylen = scale_expansion_zeroelim(cdalen, cda, pb[1], det24y); - ylen = scale_expansion_zeroelim(ylen, det24y, -pb[1], det48y); - blen = fast_expansion_sum_zeroelim(xlen, det48x, ylen, det48y, bdet); - - xlen = scale_expansion_zeroelim(dablen, dab, pc[0], det24x); - xlen = scale_expansion_zeroelim(xlen, det24x, pc[0], det48x); - ylen = scale_expansion_zeroelim(dablen, dab, pc[1], det24y); - ylen = scale_expansion_zeroelim(ylen, det24y, pc[1], det48y); - clen = fast_expansion_sum_zeroelim(xlen, det48x, ylen, det48y, cdet); - - xlen = scale_expansion_zeroelim(abclen, abc, pd[0], det24x); - xlen = scale_expansion_zeroelim(xlen, det24x, -pd[0], det48x); - ylen = scale_expansion_zeroelim(abclen, abc, pd[1], det24y); - ylen = scale_expansion_zeroelim(ylen, det24y, -pd[1], det48y); - dlen = fast_expansion_sum_zeroelim(xlen, det48x, ylen, det48y, ddet); - - ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet); - cdlen = fast_expansion_sum_zeroelim(clen, cdet, dlen, ddet, cddet); - deterlen = fast_expansion_sum_zeroelim(ablen, abdet, cdlen, cddet, deter); - - return deter[deterlen - 1]; -} - -REAL incircleslow(pa, pb, pc, pd) - REAL *pa; - REAL *pb; - REAL *pc; - REAL *pd; -{ - INEXACT REAL adx, bdx, cdx, ady, bdy, cdy; - REAL adxtail, bdxtail, cdxtail; - REAL adytail, bdytail, cdytail; - REAL negate, negatetail; - INEXACT REAL axby7, bxcy7, axcy7, bxay7, cxby7, cxay7; - REAL axby[8], bxcy[8], axcy[8], bxay[8], cxby[8], cxay[8]; - REAL temp16[16]; - int temp16len; - REAL detx[32], detxx[64], detxt[32], detxxt[64], detxtxt[64]; - int xlen, xxlen, xtlen, xxtlen, xtxtlen; - REAL x1[128], x2[192]; - int x1len, x2len; - REAL dety[32], detyy[64], detyt[32], detyyt[64], detytyt[64]; - int ylen, yylen, ytlen, yytlen, ytytlen; - REAL y1[128], y2[192]; - int y1len, y2len; - REAL adet[384], bdet[384], cdet[384], abdet[768], deter[1152]; - int alen, blen, clen, ablen, deterlen; - int i; - - INEXACT REAL bvirt; - REAL avirt, bround, around; - INEXACT REAL c; - INEXACT REAL abig; - REAL a0hi, a0lo, a1hi, a1lo, bhi, blo; - REAL err1, err2, err3; - INEXACT REAL _i, _j, _k, _l, _m, _n; - REAL _0, _1, _2; - - Two_Diff(pa[0], pd[0], adx, adxtail); - Two_Diff(pa[1], pd[1], ady, adytail); - Two_Diff(pb[0], pd[0], bdx, bdxtail); - Two_Diff(pb[1], pd[1], bdy, bdytail); - Two_Diff(pc[0], pd[0], cdx, cdxtail); - Two_Diff(pc[1], pd[1], cdy, cdytail); - - Two_Two_Product(adx, adxtail, bdy, bdytail, - axby7, axby[6], axby[5], axby[4], - axby[3], axby[2], axby[1], axby[0]); - axby[7] = axby7; - negate = -ady; - negatetail = -adytail; - Two_Two_Product(bdx, bdxtail, negate, negatetail, - bxay7, bxay[6], bxay[5], bxay[4], - bxay[3], bxay[2], bxay[1], bxay[0]); - bxay[7] = bxay7; - Two_Two_Product(bdx, bdxtail, cdy, cdytail, - bxcy7, bxcy[6], bxcy[5], bxcy[4], - bxcy[3], bxcy[2], bxcy[1], bxcy[0]); - bxcy[7] = bxcy7; - negate = -bdy; - negatetail = -bdytail; - Two_Two_Product(cdx, cdxtail, negate, negatetail, - cxby7, cxby[6], cxby[5], cxby[4], - cxby[3], cxby[2], cxby[1], cxby[0]); - cxby[7] = cxby7; - Two_Two_Product(cdx, cdxtail, ady, adytail, - cxay7, cxay[6], cxay[5], cxay[4], - cxay[3], cxay[2], cxay[1], cxay[0]); - cxay[7] = cxay7; - negate = -cdy; - negatetail = -cdytail; - Two_Two_Product(adx, adxtail, negate, negatetail, - axcy7, axcy[6], axcy[5], axcy[4], - axcy[3], axcy[2], axcy[1], axcy[0]); - axcy[7] = axcy7; - - - temp16len = fast_expansion_sum_zeroelim(8, bxcy, 8, cxby, temp16); - - xlen = scale_expansion_zeroelim(temp16len, temp16, adx, detx); - xxlen = scale_expansion_zeroelim(xlen, detx, adx, detxx); - xtlen = scale_expansion_zeroelim(temp16len, temp16, adxtail, detxt); - xxtlen = scale_expansion_zeroelim(xtlen, detxt, adx, detxxt); - for (i = 0; i < xxtlen; i++) { - detxxt[i] *= 2.0; - } - xtxtlen = scale_expansion_zeroelim(xtlen, detxt, adxtail, detxtxt); - x1len = fast_expansion_sum_zeroelim(xxlen, detxx, xxtlen, detxxt, x1); - x2len = fast_expansion_sum_zeroelim(x1len, x1, xtxtlen, detxtxt, x2); - - ylen = scale_expansion_zeroelim(temp16len, temp16, ady, dety); - yylen = scale_expansion_zeroelim(ylen, dety, ady, detyy); - ytlen = scale_expansion_zeroelim(temp16len, temp16, adytail, detyt); - yytlen = scale_expansion_zeroelim(ytlen, detyt, ady, detyyt); - for (i = 0; i < yytlen; i++) { - detyyt[i] *= 2.0; - } - ytytlen = scale_expansion_zeroelim(ytlen, detyt, adytail, detytyt); - y1len = fast_expansion_sum_zeroelim(yylen, detyy, yytlen, detyyt, y1); - y2len = fast_expansion_sum_zeroelim(y1len, y1, ytytlen, detytyt, y2); - - alen = fast_expansion_sum_zeroelim(x2len, x2, y2len, y2, adet); - - - temp16len = fast_expansion_sum_zeroelim(8, cxay, 8, axcy, temp16); - - xlen = scale_expansion_zeroelim(temp16len, temp16, bdx, detx); - xxlen = scale_expansion_zeroelim(xlen, detx, bdx, detxx); - xtlen = scale_expansion_zeroelim(temp16len, temp16, bdxtail, detxt); - xxtlen = scale_expansion_zeroelim(xtlen, detxt, bdx, detxxt); - for (i = 0; i < xxtlen; i++) { - detxxt[i] *= 2.0; - } - xtxtlen = scale_expansion_zeroelim(xtlen, detxt, bdxtail, detxtxt); - x1len = fast_expansion_sum_zeroelim(xxlen, detxx, xxtlen, detxxt, x1); - x2len = fast_expansion_sum_zeroelim(x1len, x1, xtxtlen, detxtxt, x2); - - ylen = scale_expansion_zeroelim(temp16len, temp16, bdy, dety); - yylen = scale_expansion_zeroelim(ylen, dety, bdy, detyy); - ytlen = scale_expansion_zeroelim(temp16len, temp16, bdytail, detyt); - yytlen = scale_expansion_zeroelim(ytlen, detyt, bdy, detyyt); - for (i = 0; i < yytlen; i++) { - detyyt[i] *= 2.0; - } - ytytlen = scale_expansion_zeroelim(ytlen, detyt, bdytail, detytyt); - y1len = fast_expansion_sum_zeroelim(yylen, detyy, yytlen, detyyt, y1); - y2len = fast_expansion_sum_zeroelim(y1len, y1, ytytlen, detytyt, y2); - - blen = fast_expansion_sum_zeroelim(x2len, x2, y2len, y2, bdet); - - - temp16len = fast_expansion_sum_zeroelim(8, axby, 8, bxay, temp16); - - xlen = scale_expansion_zeroelim(temp16len, temp16, cdx, detx); - xxlen = scale_expansion_zeroelim(xlen, detx, cdx, detxx); - xtlen = scale_expansion_zeroelim(temp16len, temp16, cdxtail, detxt); - xxtlen = scale_expansion_zeroelim(xtlen, detxt, cdx, detxxt); - for (i = 0; i < xxtlen; i++) { - detxxt[i] *= 2.0; - } - xtxtlen = scale_expansion_zeroelim(xtlen, detxt, cdxtail, detxtxt); - x1len = fast_expansion_sum_zeroelim(xxlen, detxx, xxtlen, detxxt, x1); - x2len = fast_expansion_sum_zeroelim(x1len, x1, xtxtlen, detxtxt, x2); - - ylen = scale_expansion_zeroelim(temp16len, temp16, cdy, dety); - yylen = scale_expansion_zeroelim(ylen, dety, cdy, detyy); - ytlen = scale_expansion_zeroelim(temp16len, temp16, cdytail, detyt); - yytlen = scale_expansion_zeroelim(ytlen, detyt, cdy, detyyt); - for (i = 0; i < yytlen; i++) { - detyyt[i] *= 2.0; - } - ytytlen = scale_expansion_zeroelim(ytlen, detyt, cdytail, detytyt); - y1len = fast_expansion_sum_zeroelim(yylen, detyy, yytlen, detyyt, y1); - y2len = fast_expansion_sum_zeroelim(y1len, y1, ytytlen, detytyt, y2); - - clen = fast_expansion_sum_zeroelim(x2len, x2, y2len, y2, cdet); - - ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet); - deterlen = fast_expansion_sum_zeroelim(ablen, abdet, clen, cdet, deter); - - return deter[deterlen - 1]; -} - -REAL incircleadapt(pa, pb, pc, pd, permanent) - REAL *pa; - REAL *pb; - REAL *pc; - REAL *pd; - REAL permanent; -{ - INEXACT REAL adx, bdx, cdx, ady, bdy, cdy; - REAL det, errbound; - - INEXACT REAL bdxcdy1, cdxbdy1, cdxady1, adxcdy1, adxbdy1, bdxady1; - REAL bdxcdy0, cdxbdy0, cdxady0, adxcdy0, adxbdy0, bdxady0; - REAL bc[4], ca[4], ab[4]; - INEXACT REAL bc3, ca3, ab3; - REAL axbc[8], axxbc[16], aybc[8], ayybc[16], adet[32]; - int axbclen, axxbclen, aybclen, ayybclen, alen; - REAL bxca[8], bxxca[16], byca[8], byyca[16], bdet[32]; - int bxcalen, bxxcalen, bycalen, byycalen, blen; - REAL cxab[8], cxxab[16], cyab[8], cyyab[16], cdet[32]; - int cxablen, cxxablen, cyablen, cyyablen, clen; - REAL abdet[64]; - int ablen; - REAL fin1[1152], fin2[1152]; - REAL *finnow, *finother, *finswap; - int finlength; - - REAL adxtail, bdxtail, cdxtail, adytail, bdytail, cdytail; - INEXACT REAL adxadx1, adyady1, bdxbdx1, bdybdy1, cdxcdx1, cdycdy1; - REAL adxadx0, adyady0, bdxbdx0, bdybdy0, cdxcdx0, cdycdy0; - REAL aa[4], bb[4], cc[4]; - INEXACT REAL aa3, bb3, cc3; - INEXACT REAL ti1, tj1; - REAL ti0, tj0; - REAL u[4], v[4]; - INEXACT REAL u3, v3; - REAL temp8[8], temp16a[16], temp16b[16], temp16c[16]; - REAL temp32a[32], temp32b[32], temp48[48], temp64[64]; - int temp8len, temp16alen, temp16blen, temp16clen; - int temp32alen, temp32blen, temp48len, temp64len; - REAL axtbb[8], axtcc[8], aytbb[8], aytcc[8]; - int axtbblen, axtcclen, aytbblen, aytcclen; - REAL bxtaa[8], bxtcc[8], bytaa[8], bytcc[8]; - int bxtaalen, bxtcclen, bytaalen, bytcclen; - REAL cxtaa[8], cxtbb[8], cytaa[8], cytbb[8]; - int cxtaalen, cxtbblen, cytaalen, cytbblen; - REAL axtbc[8], aytbc[8], bxtca[8], bytca[8], cxtab[8], cytab[8]; - int axtbclen, aytbclen, bxtcalen, bytcalen, cxtablen, cytablen; - REAL axtbct[16], aytbct[16], bxtcat[16], bytcat[16], cxtabt[16], cytabt[16]; - int axtbctlen, aytbctlen, bxtcatlen, bytcatlen, cxtabtlen, cytabtlen; - REAL axtbctt[8], aytbctt[8], bxtcatt[8]; - REAL bytcatt[8], cxtabtt[8], cytabtt[8]; - int axtbcttlen, aytbcttlen, bxtcattlen, bytcattlen, cxtabttlen, cytabttlen; - REAL abt[8], bct[8], cat[8]; - int abtlen, bctlen, catlen; - REAL abtt[4], bctt[4], catt[4]; - int abttlen, bcttlen, cattlen; - INEXACT REAL abtt3, bctt3, catt3; - REAL negate; - - INEXACT REAL bvirt; - REAL avirt, bround, around; - INEXACT REAL c; - INEXACT REAL abig; - REAL ahi, alo, bhi, blo; - REAL err1, err2, err3; - INEXACT REAL _i, _j; - REAL _0; - - adx = (REAL) (pa[0] - pd[0]); - bdx = (REAL) (pb[0] - pd[0]); - cdx = (REAL) (pc[0] - pd[0]); - ady = (REAL) (pa[1] - pd[1]); - bdy = (REAL) (pb[1] - pd[1]); - cdy = (REAL) (pc[1] - pd[1]); - - Two_Product(bdx, cdy, bdxcdy1, bdxcdy0); - Two_Product(cdx, bdy, cdxbdy1, cdxbdy0); - Two_Two_Diff(bdxcdy1, bdxcdy0, cdxbdy1, cdxbdy0, bc3, bc[2], bc[1], bc[0]); - bc[3] = bc3; - axbclen = scale_expansion_zeroelim(4, bc, adx, axbc); - axxbclen = scale_expansion_zeroelim(axbclen, axbc, adx, axxbc); - aybclen = scale_expansion_zeroelim(4, bc, ady, aybc); - ayybclen = scale_expansion_zeroelim(aybclen, aybc, ady, ayybc); - alen = fast_expansion_sum_zeroelim(axxbclen, axxbc, ayybclen, ayybc, adet); - - Two_Product(cdx, ady, cdxady1, cdxady0); - Two_Product(adx, cdy, adxcdy1, adxcdy0); - Two_Two_Diff(cdxady1, cdxady0, adxcdy1, adxcdy0, ca3, ca[2], ca[1], ca[0]); - ca[3] = ca3; - bxcalen = scale_expansion_zeroelim(4, ca, bdx, bxca); - bxxcalen = scale_expansion_zeroelim(bxcalen, bxca, bdx, bxxca); - bycalen = scale_expansion_zeroelim(4, ca, bdy, byca); - byycalen = scale_expansion_zeroelim(bycalen, byca, bdy, byyca); - blen = fast_expansion_sum_zeroelim(bxxcalen, bxxca, byycalen, byyca, bdet); - - Two_Product(adx, bdy, adxbdy1, adxbdy0); - Two_Product(bdx, ady, bdxady1, bdxady0); - Two_Two_Diff(adxbdy1, adxbdy0, bdxady1, bdxady0, ab3, ab[2], ab[1], ab[0]); - ab[3] = ab3; - cxablen = scale_expansion_zeroelim(4, ab, cdx, cxab); - cxxablen = scale_expansion_zeroelim(cxablen, cxab, cdx, cxxab); - cyablen = scale_expansion_zeroelim(4, ab, cdy, cyab); - cyyablen = scale_expansion_zeroelim(cyablen, cyab, cdy, cyyab); - clen = fast_expansion_sum_zeroelim(cxxablen, cxxab, cyyablen, cyyab, cdet); - - ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet); - finlength = fast_expansion_sum_zeroelim(ablen, abdet, clen, cdet, fin1); - - det = estimate(finlength, fin1); - errbound = iccerrboundB * permanent; - if ((det >= errbound) || (-det >= errbound)) { - return det; - } - - Two_Diff_Tail(pa[0], pd[0], adx, adxtail); - Two_Diff_Tail(pa[1], pd[1], ady, adytail); - Two_Diff_Tail(pb[0], pd[0], bdx, bdxtail); - Two_Diff_Tail(pb[1], pd[1], bdy, bdytail); - Two_Diff_Tail(pc[0], pd[0], cdx, cdxtail); - Two_Diff_Tail(pc[1], pd[1], cdy, cdytail); - if ((adxtail == 0.0) && (bdxtail == 0.0) && (cdxtail == 0.0) - && (adytail == 0.0) && (bdytail == 0.0) && (cdytail == 0.0)) { - return det; - } - - errbound = iccerrboundC * permanent + resulterrbound * Absolute(det); - det += ((adx * adx + ady * ady) * ((bdx * cdytail + cdy * bdxtail) - - (bdy * cdxtail + cdx * bdytail)) - + 2.0 * (adx * adxtail + ady * adytail) * (bdx * cdy - bdy * cdx)) - + ((bdx * bdx + bdy * bdy) * ((cdx * adytail + ady * cdxtail) - - (cdy * adxtail + adx * cdytail)) - + 2.0 * (bdx * bdxtail + bdy * bdytail) * (cdx * ady - cdy * adx)) - + ((cdx * cdx + cdy * cdy) * ((adx * bdytail + bdy * adxtail) - - (ady * bdxtail + bdx * adytail)) - + 2.0 * (cdx * cdxtail + cdy * cdytail) * (adx * bdy - ady * bdx)); - if ((det >= errbound) || (-det >= errbound)) { - return det; - } - - finnow = fin1; - finother = fin2; - - if ((bdxtail != 0.0) || (bdytail != 0.0) - || (cdxtail != 0.0) || (cdytail != 0.0)) { - Square(adx, adxadx1, adxadx0); - Square(ady, adyady1, adyady0); - Two_Two_Sum(adxadx1, adxadx0, adyady1, adyady0, aa3, aa[2], aa[1], aa[0]); - aa[3] = aa3; - } - if ((cdxtail != 0.0) || (cdytail != 0.0) - || (adxtail != 0.0) || (adytail != 0.0)) { - Square(bdx, bdxbdx1, bdxbdx0); - Square(bdy, bdybdy1, bdybdy0); - Two_Two_Sum(bdxbdx1, bdxbdx0, bdybdy1, bdybdy0, bb3, bb[2], bb[1], bb[0]); - bb[3] = bb3; - } - if ((adxtail != 0.0) || (adytail != 0.0) - || (bdxtail != 0.0) || (bdytail != 0.0)) { - Square(cdx, cdxcdx1, cdxcdx0); - Square(cdy, cdycdy1, cdycdy0); - Two_Two_Sum(cdxcdx1, cdxcdx0, cdycdy1, cdycdy0, cc3, cc[2], cc[1], cc[0]); - cc[3] = cc3; - } - - if (adxtail != 0.0) { - axtbclen = scale_expansion_zeroelim(4, bc, adxtail, axtbc); - temp16alen = scale_expansion_zeroelim(axtbclen, axtbc, 2.0 * adx, - temp16a); - - axtcclen = scale_expansion_zeroelim(4, cc, adxtail, axtcc); - temp16blen = scale_expansion_zeroelim(axtcclen, axtcc, bdy, temp16b); - - axtbblen = scale_expansion_zeroelim(4, bb, adxtail, axtbb); - temp16clen = scale_expansion_zeroelim(axtbblen, axtbb, -cdy, temp16c); - - temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp16blen, temp16b, temp32a); - temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, - temp32alen, temp32a, temp48); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, - temp48, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - if (adytail != 0.0) { - aytbclen = scale_expansion_zeroelim(4, bc, adytail, aytbc); - temp16alen = scale_expansion_zeroelim(aytbclen, aytbc, 2.0 * ady, - temp16a); - - aytbblen = scale_expansion_zeroelim(4, bb, adytail, aytbb); - temp16blen = scale_expansion_zeroelim(aytbblen, aytbb, cdx, temp16b); - - aytcclen = scale_expansion_zeroelim(4, cc, adytail, aytcc); - temp16clen = scale_expansion_zeroelim(aytcclen, aytcc, -bdx, temp16c); - - temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp16blen, temp16b, temp32a); - temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, - temp32alen, temp32a, temp48); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, - temp48, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - if (bdxtail != 0.0) { - bxtcalen = scale_expansion_zeroelim(4, ca, bdxtail, bxtca); - temp16alen = scale_expansion_zeroelim(bxtcalen, bxtca, 2.0 * bdx, - temp16a); - - bxtaalen = scale_expansion_zeroelim(4, aa, bdxtail, bxtaa); - temp16blen = scale_expansion_zeroelim(bxtaalen, bxtaa, cdy, temp16b); - - bxtcclen = scale_expansion_zeroelim(4, cc, bdxtail, bxtcc); - temp16clen = scale_expansion_zeroelim(bxtcclen, bxtcc, -ady, temp16c); - - temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp16blen, temp16b, temp32a); - temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, - temp32alen, temp32a, temp48); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, - temp48, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - if (bdytail != 0.0) { - bytcalen = scale_expansion_zeroelim(4, ca, bdytail, bytca); - temp16alen = scale_expansion_zeroelim(bytcalen, bytca, 2.0 * bdy, - temp16a); - - bytcclen = scale_expansion_zeroelim(4, cc, bdytail, bytcc); - temp16blen = scale_expansion_zeroelim(bytcclen, bytcc, adx, temp16b); - - bytaalen = scale_expansion_zeroelim(4, aa, bdytail, bytaa); - temp16clen = scale_expansion_zeroelim(bytaalen, bytaa, -cdx, temp16c); - - temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp16blen, temp16b, temp32a); - temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, - temp32alen, temp32a, temp48); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, - temp48, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - if (cdxtail != 0.0) { - cxtablen = scale_expansion_zeroelim(4, ab, cdxtail, cxtab); - temp16alen = scale_expansion_zeroelim(cxtablen, cxtab, 2.0 * cdx, - temp16a); - - cxtbblen = scale_expansion_zeroelim(4, bb, cdxtail, cxtbb); - temp16blen = scale_expansion_zeroelim(cxtbblen, cxtbb, ady, temp16b); - - cxtaalen = scale_expansion_zeroelim(4, aa, cdxtail, cxtaa); - temp16clen = scale_expansion_zeroelim(cxtaalen, cxtaa, -bdy, temp16c); - - temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp16blen, temp16b, temp32a); - temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, - temp32alen, temp32a, temp48); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, - temp48, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - if (cdytail != 0.0) { - cytablen = scale_expansion_zeroelim(4, ab, cdytail, cytab); - temp16alen = scale_expansion_zeroelim(cytablen, cytab, 2.0 * cdy, - temp16a); - - cytaalen = scale_expansion_zeroelim(4, aa, cdytail, cytaa); - temp16blen = scale_expansion_zeroelim(cytaalen, cytaa, bdx, temp16b); - - cytbblen = scale_expansion_zeroelim(4, bb, cdytail, cytbb); - temp16clen = scale_expansion_zeroelim(cytbblen, cytbb, -adx, temp16c); - - temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp16blen, temp16b, temp32a); - temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, - temp32alen, temp32a, temp48); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, - temp48, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - - if ((adxtail != 0.0) || (adytail != 0.0)) { - if ((bdxtail != 0.0) || (bdytail != 0.0) - || (cdxtail != 0.0) || (cdytail != 0.0)) { - Two_Product(bdxtail, cdy, ti1, ti0); - Two_Product(bdx, cdytail, tj1, tj0); - Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]); - u[3] = u3; - negate = -bdy; - Two_Product(cdxtail, negate, ti1, ti0); - negate = -bdytail; - Two_Product(cdx, negate, tj1, tj0); - Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]); - v[3] = v3; - bctlen = fast_expansion_sum_zeroelim(4, u, 4, v, bct); - - Two_Product(bdxtail, cdytail, ti1, ti0); - Two_Product(cdxtail, bdytail, tj1, tj0); - Two_Two_Diff(ti1, ti0, tj1, tj0, bctt3, bctt[2], bctt[1], bctt[0]); - bctt[3] = bctt3; - bcttlen = 4; - } else { - bct[0] = 0.0; - bctlen = 1; - bctt[0] = 0.0; - bcttlen = 1; - } - - if (adxtail != 0.0) { - temp16alen = scale_expansion_zeroelim(axtbclen, axtbc, adxtail, temp16a); - axtbctlen = scale_expansion_zeroelim(bctlen, bct, adxtail, axtbct); - temp32alen = scale_expansion_zeroelim(axtbctlen, axtbct, 2.0 * adx, - temp32a); - temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp32alen, temp32a, temp48); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, - temp48, finother); - finswap = finnow; finnow = finother; finother = finswap; - if (bdytail != 0.0) { - temp8len = scale_expansion_zeroelim(4, cc, adxtail, temp8); - temp16alen = scale_expansion_zeroelim(temp8len, temp8, bdytail, - temp16a); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, - temp16a, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - if (cdytail != 0.0) { - temp8len = scale_expansion_zeroelim(4, bb, -adxtail, temp8); - temp16alen = scale_expansion_zeroelim(temp8len, temp8, cdytail, - temp16a); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, - temp16a, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - - temp32alen = scale_expansion_zeroelim(axtbctlen, axtbct, adxtail, - temp32a); - axtbcttlen = scale_expansion_zeroelim(bcttlen, bctt, adxtail, axtbctt); - temp16alen = scale_expansion_zeroelim(axtbcttlen, axtbctt, 2.0 * adx, - temp16a); - temp16blen = scale_expansion_zeroelim(axtbcttlen, axtbctt, adxtail, - temp16b); - temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp16blen, temp16b, temp32b); - temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, - temp32blen, temp32b, temp64); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, - temp64, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - if (adytail != 0.0) { -#ifndef WIN32 -#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" -#endif - temp16alen = scale_expansion_zeroelim(aytbclen, aytbc, adytail, temp16a); - aytbctlen = scale_expansion_zeroelim(bctlen, bct, adytail, aytbct); - temp32alen = scale_expansion_zeroelim(aytbctlen, aytbct, 2.0 * ady, - temp32a); - temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp32alen, temp32a, temp48); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, - temp48, finother); - finswap = finnow; finnow = finother; finother = finswap; - - - temp32alen = scale_expansion_zeroelim(aytbctlen, aytbct, adytail, - temp32a); - aytbcttlen = scale_expansion_zeroelim(bcttlen, bctt, adytail, aytbctt); - temp16alen = scale_expansion_zeroelim(aytbcttlen, aytbctt, 2.0 * ady, - temp16a); - temp16blen = scale_expansion_zeroelim(aytbcttlen, aytbctt, adytail, - temp16b); - temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp16blen, temp16b, temp32b); - temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, - temp32blen, temp32b, temp64); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, - temp64, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - } - if ((bdxtail != 0.0) || (bdytail != 0.0)) { - if ((cdxtail != 0.0) || (cdytail != 0.0) - || (adxtail != 0.0) || (adytail != 0.0)) { - Two_Product(cdxtail, ady, ti1, ti0); - Two_Product(cdx, adytail, tj1, tj0); - Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]); - u[3] = u3; - negate = -cdy; - Two_Product(adxtail, negate, ti1, ti0); - negate = -cdytail; - Two_Product(adx, negate, tj1, tj0); - Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]); - v[3] = v3; - catlen = fast_expansion_sum_zeroelim(4, u, 4, v, cat); - - Two_Product(cdxtail, adytail, ti1, ti0); - Two_Product(adxtail, cdytail, tj1, tj0); - Two_Two_Diff(ti1, ti0, tj1, tj0, catt3, catt[2], catt[1], catt[0]); - catt[3] = catt3; - cattlen = 4; - } else { - cat[0] = 0.0; - catlen = 1; - catt[0] = 0.0; - cattlen = 1; - } - - if (bdxtail != 0.0) { - temp16alen = scale_expansion_zeroelim(bxtcalen, bxtca, bdxtail, temp16a); - bxtcatlen = scale_expansion_zeroelim(catlen, cat, bdxtail, bxtcat); - temp32alen = scale_expansion_zeroelim(bxtcatlen, bxtcat, 2.0 * bdx, - temp32a); - temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp32alen, temp32a, temp48); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, - temp48, finother); - finswap = finnow; finnow = finother; finother = finswap; - if (cdytail != 0.0) { - temp8len = scale_expansion_zeroelim(4, aa, bdxtail, temp8); - temp16alen = scale_expansion_zeroelim(temp8len, temp8, cdytail, - temp16a); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, - temp16a, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - if (adytail != 0.0) { - temp8len = scale_expansion_zeroelim(4, cc, -bdxtail, temp8); - temp16alen = scale_expansion_zeroelim(temp8len, temp8, adytail, - temp16a); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, - temp16a, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - - temp32alen = scale_expansion_zeroelim(bxtcatlen, bxtcat, bdxtail, - temp32a); - bxtcattlen = scale_expansion_zeroelim(cattlen, catt, bdxtail, bxtcatt); - temp16alen = scale_expansion_zeroelim(bxtcattlen, bxtcatt, 2.0 * bdx, - temp16a); - temp16blen = scale_expansion_zeroelim(bxtcattlen, bxtcatt, bdxtail, - temp16b); - temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp16blen, temp16b, temp32b); - temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, - temp32blen, temp32b, temp64); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, - temp64, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - if (bdytail != 0.0) { -#ifndef WIN32 -#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" -#endif - temp16alen = scale_expansion_zeroelim(bytcalen, bytca, bdytail, temp16a); - bytcatlen = scale_expansion_zeroelim(catlen, cat, bdytail, bytcat); - temp32alen = scale_expansion_zeroelim(bytcatlen, bytcat, 2.0 * bdy, - temp32a); - temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp32alen, temp32a, temp48); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, - temp48, finother); - finswap = finnow; finnow = finother; finother = finswap; - - - temp32alen = scale_expansion_zeroelim(bytcatlen, bytcat, bdytail, - temp32a); - bytcattlen = scale_expansion_zeroelim(cattlen, catt, bdytail, bytcatt); - temp16alen = scale_expansion_zeroelim(bytcattlen, bytcatt, 2.0 * bdy, - temp16a); - temp16blen = scale_expansion_zeroelim(bytcattlen, bytcatt, bdytail, - temp16b); - temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp16blen, temp16b, temp32b); - temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, - temp32blen, temp32b, temp64); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, - temp64, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - } - if ((cdxtail != 0.0) || (cdytail != 0.0)) { - if ((adxtail != 0.0) || (adytail != 0.0) - || (bdxtail != 0.0) || (bdytail != 0.0)) { - Two_Product(adxtail, bdy, ti1, ti0); - Two_Product(adx, bdytail, tj1, tj0); - Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]); - u[3] = u3; - negate = -ady; - Two_Product(bdxtail, negate, ti1, ti0); - negate = -adytail; - Two_Product(bdx, negate, tj1, tj0); - Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]); - v[3] = v3; - abtlen = fast_expansion_sum_zeroelim(4, u, 4, v, abt); - - Two_Product(adxtail, bdytail, ti1, ti0); - Two_Product(bdxtail, adytail, tj1, tj0); - Two_Two_Diff(ti1, ti0, tj1, tj0, abtt3, abtt[2], abtt[1], abtt[0]); - abtt[3] = abtt3; - abttlen = 4; - } else { - abt[0] = 0.0; - abtlen = 1; - abtt[0] = 0.0; - abttlen = 1; - } - - if (cdxtail != 0.0) { -#ifndef WIN32 -#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" -#endif - temp16alen = scale_expansion_zeroelim(cxtablen, cxtab, cdxtail, temp16a); - cxtabtlen = scale_expansion_zeroelim(abtlen, abt, cdxtail, cxtabt); - temp32alen = scale_expansion_zeroelim(cxtabtlen, cxtabt, 2.0 * cdx, - temp32a); - temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp32alen, temp32a, temp48); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, - temp48, finother); - finswap = finnow; finnow = finother; finother = finswap; - if (adytail != 0.0) { - temp8len = scale_expansion_zeroelim(4, bb, cdxtail, temp8); - temp16alen = scale_expansion_zeroelim(temp8len, temp8, adytail, - temp16a); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, - temp16a, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - if (bdytail != 0.0) { - temp8len = scale_expansion_zeroelim(4, aa, -cdxtail, temp8); - temp16alen = scale_expansion_zeroelim(temp8len, temp8, bdytail, - temp16a); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, - temp16a, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - - temp32alen = scale_expansion_zeroelim(cxtabtlen, cxtabt, cdxtail, - temp32a); - cxtabttlen = scale_expansion_zeroelim(abttlen, abtt, cdxtail, cxtabtt); - temp16alen = scale_expansion_zeroelim(cxtabttlen, cxtabtt, 2.0 * cdx, - temp16a); - temp16blen = scale_expansion_zeroelim(cxtabttlen, cxtabtt, cdxtail, - temp16b); - temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp16blen, temp16b, temp32b); - temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, - temp32blen, temp32b, temp64); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, - temp64, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - if (cdytail != 0.0) { -#ifndef WIN32 -#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" -#endif - temp16alen = scale_expansion_zeroelim(cytablen, cytab, cdytail, temp16a); - cytabtlen = scale_expansion_zeroelim(abtlen, abt, cdytail, cytabt); - temp32alen = scale_expansion_zeroelim(cytabtlen, cytabt, 2.0 * cdy, - temp32a); - temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp32alen, temp32a, temp48); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, - temp48, finother); - finswap = finnow; finnow = finother; finother = finswap; - - - temp32alen = scale_expansion_zeroelim(cytabtlen, cytabt, cdytail, - temp32a); - cytabttlen = scale_expansion_zeroelim(abttlen, abtt, cdytail, cytabtt); - temp16alen = scale_expansion_zeroelim(cytabttlen, cytabtt, 2.0 * cdy, - temp16a); - temp16blen = scale_expansion_zeroelim(cytabttlen, cytabtt, cdytail, - temp16b); - temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp16blen, temp16b, temp32b); - temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, - temp32blen, temp32b, temp64); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, - temp64, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - } - - return finnow[finlength - 1]; -} - -REAL incircle(pa, pb, pc, pd) - REAL *pa; - REAL *pb; - REAL *pc; - REAL *pd; -{ - REAL adx, bdx, cdx, ady, bdy, cdy; - REAL bdxcdy, cdxbdy, cdxady, adxcdy, adxbdy, bdxady; - REAL alift, blift, clift; - REAL det; - REAL permanent, errbound; - - adx = pa[0] - pd[0]; - bdx = pb[0] - pd[0]; - cdx = pc[0] - pd[0]; - ady = pa[1] - pd[1]; - bdy = pb[1] - pd[1]; - cdy = pc[1] - pd[1]; - - bdxcdy = bdx * cdy; - cdxbdy = cdx * bdy; - alift = adx * adx + ady * ady; - - cdxady = cdx * ady; - adxcdy = adx * cdy; - blift = bdx * bdx + bdy * bdy; - - adxbdy = adx * bdy; - bdxady = bdx * ady; - clift = cdx * cdx + cdy * cdy; - - det = alift * (bdxcdy - cdxbdy) - + blift * (cdxady - adxcdy) - + clift * (adxbdy - bdxady); - - permanent = (Absolute(bdxcdy) + Absolute(cdxbdy)) * alift - + (Absolute(cdxady) + Absolute(adxcdy)) * blift - + (Absolute(adxbdy) + Absolute(bdxady)) * clift; - errbound = iccerrboundA * permanent; - if ((det > errbound) || (-det > errbound)) { - return det; - } - - return incircleadapt(pa, pb, pc, pd, permanent); -} - -/*****************************************************************************/ -/* */ -/* inspherefast() Approximate 3D insphere test. Nonrobust. */ -/* insphereexact() Exact 3D insphere test. Robust. */ -/* insphereslow() Another exact 3D insphere test. Robust. */ -/* insphere() Adaptive exact 3D insphere test. Robust. */ -/* */ -/* Return a positive value if the point pe lies inside the */ -/* sphere passing through pa, pb, pc, and pd; a negative value */ -/* if it lies outside; and zero if the five points are */ -/* cospherical. The points pa, pb, pc, and pd must be ordered */ -/* so that they have a positive orientation (as defined by */ -/* orient3d()), or the sign of the result will be reversed. */ -/* */ -/* Only the first and last routine should be used; the middle two are for */ -/* timings. */ -/* */ -/* The last three use exact arithmetic to ensure a correct answer. The */ -/* result returned is the determinant of a matrix. In insphere() only, */ -/* this determinant is computed adaptively, in the sense that exact */ -/* arithmetic is used only to the degree it is needed to ensure that the */ -/* returned value has the correct sign. Hence, insphere() is usually quite */ -/* fast, but will run more slowly when the input points are cospherical or */ -/* nearly so. */ -/* */ -/*****************************************************************************/ - -REAL inspherefast(pa, pb, pc, pd, pe) - REAL *pa; - REAL *pb; - REAL *pc; - REAL *pd; - REAL *pe; -{ - REAL aex, bex, cex, dex; - REAL aey, bey, cey, dey; - REAL aez, bez, cez, dez; - REAL alift, blift, clift, dlift; - REAL ab, bc, cd, da, ac, bd; - REAL abc, bcd, cda, dab; - - aex = pa[0] - pe[0]; - bex = pb[0] - pe[0]; - cex = pc[0] - pe[0]; - dex = pd[0] - pe[0]; - aey = pa[1] - pe[1]; - bey = pb[1] - pe[1]; - cey = pc[1] - pe[1]; - dey = pd[1] - pe[1]; - aez = pa[2] - pe[2]; - bez = pb[2] - pe[2]; - cez = pc[2] - pe[2]; - dez = pd[2] - pe[2]; - - ab = aex * bey - bex * aey; - bc = bex * cey - cex * bey; - cd = cex * dey - dex * cey; - da = dex * aey - aex * dey; - - ac = aex * cey - cex * aey; - bd = bex * dey - dex * bey; - - abc = aez * bc - bez * ac + cez * ab; - bcd = bez * cd - cez * bd + dez * bc; - cda = cez * da + dez * ac + aez * cd; - dab = dez * ab + aez * bd + bez * da; - - alift = aex * aex + aey * aey + aez * aez; - blift = bex * bex + bey * bey + bez * bez; - clift = cex * cex + cey * cey + cez * cez; - dlift = dex * dex + dey * dey + dez * dez; - - return (dlift * abc - clift * dab) + (blift * cda - alift * bcd); -} - -REAL insphereexact(pa, pb, pc, pd, pe) - REAL *pa; - REAL *pb; - REAL *pc; - REAL *pd; - REAL *pe; -{ - INEXACT REAL axby1, bxcy1, cxdy1, dxey1, exay1; - INEXACT REAL bxay1, cxby1, dxcy1, exdy1, axey1; - INEXACT REAL axcy1, bxdy1, cxey1, dxay1, exby1; - INEXACT REAL cxay1, dxby1, excy1, axdy1, bxey1; - REAL axby0, bxcy0, cxdy0, dxey0, exay0; - REAL bxay0, cxby0, dxcy0, exdy0, axey0; - REAL axcy0, bxdy0, cxey0, dxay0, exby0; - REAL cxay0, dxby0, excy0, axdy0, bxey0; - REAL ab[4], bc[4], cd[4], de[4], ea[4]; - REAL ac[4], bd[4], ce[4], da[4], eb[4]; - REAL temp8a[8], temp8b[8], temp16[16]; - int temp8alen, temp8blen, temp16len; - REAL abc[24], bcd[24], cde[24], dea[24], eab[24]; - REAL abd[24], bce[24], cda[24], deb[24], eac[24]; - int abclen, bcdlen, cdelen, dealen, eablen; - int abdlen, bcelen, cdalen, deblen, eaclen; - REAL temp48a[48], temp48b[48]; - int temp48alen, temp48blen; - REAL abcd[96], bcde[96], cdea[96], deab[96], eabc[96]; - int abcdlen, bcdelen, cdealen, deablen, eabclen; - REAL temp192[192]; - REAL det384x[384], det384y[384], det384z[384]; - int xlen, ylen, zlen; - REAL detxy[768]; - int xylen; - REAL adet[1152], bdet[1152], cdet[1152], ddet[1152], edet[1152]; - int alen, blen, clen, dlen, elen; - REAL abdet[2304], cddet[2304], cdedet[3456]; - int ablen, cdlen; - REAL deter[5760]; - int deterlen; - int i; - - INEXACT REAL bvirt; - REAL avirt, bround, around; - INEXACT REAL c; - INEXACT REAL abig; - REAL ahi, alo, bhi, blo; - REAL err1, err2, err3; - INEXACT REAL _i, _j; - REAL _0; - - Two_Product(pa[0], pb[1], axby1, axby0); - Two_Product(pb[0], pa[1], bxay1, bxay0); - Two_Two_Diff(axby1, axby0, bxay1, bxay0, ab[3], ab[2], ab[1], ab[0]); - - Two_Product(pb[0], pc[1], bxcy1, bxcy0); - Two_Product(pc[0], pb[1], cxby1, cxby0); - Two_Two_Diff(bxcy1, bxcy0, cxby1, cxby0, bc[3], bc[2], bc[1], bc[0]); - - Two_Product(pc[0], pd[1], cxdy1, cxdy0); - Two_Product(pd[0], pc[1], dxcy1, dxcy0); - Two_Two_Diff(cxdy1, cxdy0, dxcy1, dxcy0, cd[3], cd[2], cd[1], cd[0]); - - Two_Product(pd[0], pe[1], dxey1, dxey0); - Two_Product(pe[0], pd[1], exdy1, exdy0); - Two_Two_Diff(dxey1, dxey0, exdy1, exdy0, de[3], de[2], de[1], de[0]); - - Two_Product(pe[0], pa[1], exay1, exay0); - Two_Product(pa[0], pe[1], axey1, axey0); - Two_Two_Diff(exay1, exay0, axey1, axey0, ea[3], ea[2], ea[1], ea[0]); - - Two_Product(pa[0], pc[1], axcy1, axcy0); - Two_Product(pc[0], pa[1], cxay1, cxay0); - Two_Two_Diff(axcy1, axcy0, cxay1, cxay0, ac[3], ac[2], ac[1], ac[0]); - - Two_Product(pb[0], pd[1], bxdy1, bxdy0); - Two_Product(pd[0], pb[1], dxby1, dxby0); - Two_Two_Diff(bxdy1, bxdy0, dxby1, dxby0, bd[3], bd[2], bd[1], bd[0]); - - Two_Product(pc[0], pe[1], cxey1, cxey0); - Two_Product(pe[0], pc[1], excy1, excy0); - Two_Two_Diff(cxey1, cxey0, excy1, excy0, ce[3], ce[2], ce[1], ce[0]); - - Two_Product(pd[0], pa[1], dxay1, dxay0); - Two_Product(pa[0], pd[1], axdy1, axdy0); - Two_Two_Diff(dxay1, dxay0, axdy1, axdy0, da[3], da[2], da[1], da[0]); - - Two_Product(pe[0], pb[1], exby1, exby0); - Two_Product(pb[0], pe[1], bxey1, bxey0); - Two_Two_Diff(exby1, exby0, bxey1, bxey0, eb[3], eb[2], eb[1], eb[0]); - - temp8alen = scale_expansion_zeroelim(4, bc, pa[2], temp8a); - temp8blen = scale_expansion_zeroelim(4, ac, -pb[2], temp8b); - temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, - temp16); - temp8alen = scale_expansion_zeroelim(4, ab, pc[2], temp8a); - abclen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, - abc); - - temp8alen = scale_expansion_zeroelim(4, cd, pb[2], temp8a); - temp8blen = scale_expansion_zeroelim(4, bd, -pc[2], temp8b); - temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, - temp16); - temp8alen = scale_expansion_zeroelim(4, bc, pd[2], temp8a); - bcdlen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, - bcd); - - temp8alen = scale_expansion_zeroelim(4, de, pc[2], temp8a); - temp8blen = scale_expansion_zeroelim(4, ce, -pd[2], temp8b); - temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, - temp16); - temp8alen = scale_expansion_zeroelim(4, cd, pe[2], temp8a); - cdelen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, - cde); - - temp8alen = scale_expansion_zeroelim(4, ea, pd[2], temp8a); - temp8blen = scale_expansion_zeroelim(4, da, -pe[2], temp8b); - temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, - temp16); - temp8alen = scale_expansion_zeroelim(4, de, pa[2], temp8a); - dealen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, - dea); - - temp8alen = scale_expansion_zeroelim(4, ab, pe[2], temp8a); - temp8blen = scale_expansion_zeroelim(4, eb, -pa[2], temp8b); - temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, - temp16); - temp8alen = scale_expansion_zeroelim(4, ea, pb[2], temp8a); - eablen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, - eab); - - temp8alen = scale_expansion_zeroelim(4, bd, pa[2], temp8a); - temp8blen = scale_expansion_zeroelim(4, da, pb[2], temp8b); - temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, - temp16); - temp8alen = scale_expansion_zeroelim(4, ab, pd[2], temp8a); - abdlen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, - abd); - - temp8alen = scale_expansion_zeroelim(4, ce, pb[2], temp8a); - temp8blen = scale_expansion_zeroelim(4, eb, pc[2], temp8b); - temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, - temp16); - temp8alen = scale_expansion_zeroelim(4, bc, pe[2], temp8a); - bcelen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, - bce); - - temp8alen = scale_expansion_zeroelim(4, da, pc[2], temp8a); - temp8blen = scale_expansion_zeroelim(4, ac, pd[2], temp8b); - temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, - temp16); - temp8alen = scale_expansion_zeroelim(4, cd, pa[2], temp8a); - cdalen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, - cda); - - temp8alen = scale_expansion_zeroelim(4, eb, pd[2], temp8a); - temp8blen = scale_expansion_zeroelim(4, bd, pe[2], temp8b); - temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, - temp16); - temp8alen = scale_expansion_zeroelim(4, de, pb[2], temp8a); - deblen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, - deb); - - temp8alen = scale_expansion_zeroelim(4, ac, pe[2], temp8a); - temp8blen = scale_expansion_zeroelim(4, ce, pa[2], temp8b); - temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, - temp16); - temp8alen = scale_expansion_zeroelim(4, ea, pc[2], temp8a); - eaclen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, - eac); - - temp48alen = fast_expansion_sum_zeroelim(cdelen, cde, bcelen, bce, temp48a); - temp48blen = fast_expansion_sum_zeroelim(deblen, deb, bcdlen, bcd, temp48b); - for (i = 0; i < temp48blen; i++) { - temp48b[i] = -temp48b[i]; - } - bcdelen = fast_expansion_sum_zeroelim(temp48alen, temp48a, - temp48blen, temp48b, bcde); - xlen = scale_expansion_zeroelim(bcdelen, bcde, pa[0], temp192); - xlen = scale_expansion_zeroelim(xlen, temp192, pa[0], det384x); - ylen = scale_expansion_zeroelim(bcdelen, bcde, pa[1], temp192); - ylen = scale_expansion_zeroelim(ylen, temp192, pa[1], det384y); - zlen = scale_expansion_zeroelim(bcdelen, bcde, pa[2], temp192); - zlen = scale_expansion_zeroelim(zlen, temp192, pa[2], det384z); - xylen = fast_expansion_sum_zeroelim(xlen, det384x, ylen, det384y, detxy); - alen = fast_expansion_sum_zeroelim(xylen, detxy, zlen, det384z, adet); - - temp48alen = fast_expansion_sum_zeroelim(dealen, dea, cdalen, cda, temp48a); - temp48blen = fast_expansion_sum_zeroelim(eaclen, eac, cdelen, cde, temp48b); - for (i = 0; i < temp48blen; i++) { - temp48b[i] = -temp48b[i]; - } - cdealen = fast_expansion_sum_zeroelim(temp48alen, temp48a, - temp48blen, temp48b, cdea); - xlen = scale_expansion_zeroelim(cdealen, cdea, pb[0], temp192); - xlen = scale_expansion_zeroelim(xlen, temp192, pb[0], det384x); - ylen = scale_expansion_zeroelim(cdealen, cdea, pb[1], temp192); - ylen = scale_expansion_zeroelim(ylen, temp192, pb[1], det384y); - zlen = scale_expansion_zeroelim(cdealen, cdea, pb[2], temp192); - zlen = scale_expansion_zeroelim(zlen, temp192, pb[2], det384z); - xylen = fast_expansion_sum_zeroelim(xlen, det384x, ylen, det384y, detxy); - blen = fast_expansion_sum_zeroelim(xylen, detxy, zlen, det384z, bdet); - - temp48alen = fast_expansion_sum_zeroelim(eablen, eab, deblen, deb, temp48a); - temp48blen = fast_expansion_sum_zeroelim(abdlen, abd, dealen, dea, temp48b); - for (i = 0; i < temp48blen; i++) { - temp48b[i] = -temp48b[i]; - } - deablen = fast_expansion_sum_zeroelim(temp48alen, temp48a, - temp48blen, temp48b, deab); - xlen = scale_expansion_zeroelim(deablen, deab, pc[0], temp192); - xlen = scale_expansion_zeroelim(xlen, temp192, pc[0], det384x); - ylen = scale_expansion_zeroelim(deablen, deab, pc[1], temp192); - ylen = scale_expansion_zeroelim(ylen, temp192, pc[1], det384y); - zlen = scale_expansion_zeroelim(deablen, deab, pc[2], temp192); - zlen = scale_expansion_zeroelim(zlen, temp192, pc[2], det384z); - xylen = fast_expansion_sum_zeroelim(xlen, det384x, ylen, det384y, detxy); - clen = fast_expansion_sum_zeroelim(xylen, detxy, zlen, det384z, cdet); - - temp48alen = fast_expansion_sum_zeroelim(abclen, abc, eaclen, eac, temp48a); - temp48blen = fast_expansion_sum_zeroelim(bcelen, bce, eablen, eab, temp48b); - for (i = 0; i < temp48blen; i++) { - temp48b[i] = -temp48b[i]; - } - eabclen = fast_expansion_sum_zeroelim(temp48alen, temp48a, - temp48blen, temp48b, eabc); - xlen = scale_expansion_zeroelim(eabclen, eabc, pd[0], temp192); - xlen = scale_expansion_zeroelim(xlen, temp192, pd[0], det384x); - ylen = scale_expansion_zeroelim(eabclen, eabc, pd[1], temp192); - ylen = scale_expansion_zeroelim(ylen, temp192, pd[1], det384y); - zlen = scale_expansion_zeroelim(eabclen, eabc, pd[2], temp192); - zlen = scale_expansion_zeroelim(zlen, temp192, pd[2], det384z); - xylen = fast_expansion_sum_zeroelim(xlen, det384x, ylen, det384y, detxy); - dlen = fast_expansion_sum_zeroelim(xylen, detxy, zlen, det384z, ddet); - - temp48alen = fast_expansion_sum_zeroelim(bcdlen, bcd, abdlen, abd, temp48a); - temp48blen = fast_expansion_sum_zeroelim(cdalen, cda, abclen, abc, temp48b); - for (i = 0; i < temp48blen; i++) { - temp48b[i] = -temp48b[i]; - } - abcdlen = fast_expansion_sum_zeroelim(temp48alen, temp48a, - temp48blen, temp48b, abcd); - xlen = scale_expansion_zeroelim(abcdlen, abcd, pe[0], temp192); - xlen = scale_expansion_zeroelim(xlen, temp192, pe[0], det384x); - ylen = scale_expansion_zeroelim(abcdlen, abcd, pe[1], temp192); - ylen = scale_expansion_zeroelim(ylen, temp192, pe[1], det384y); - zlen = scale_expansion_zeroelim(abcdlen, abcd, pe[2], temp192); - zlen = scale_expansion_zeroelim(zlen, temp192, pe[2], det384z); - xylen = fast_expansion_sum_zeroelim(xlen, det384x, ylen, det384y, detxy); - elen = fast_expansion_sum_zeroelim(xylen, detxy, zlen, det384z, edet); - - ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet); - cdlen = fast_expansion_sum_zeroelim(clen, cdet, dlen, ddet, cddet); - cdelen = fast_expansion_sum_zeroelim(cdlen, cddet, elen, edet, cdedet); - deterlen = fast_expansion_sum_zeroelim(ablen, abdet, cdelen, cdedet, deter); - - return deter[deterlen - 1]; -} - -REAL insphereslow(pa, pb, pc, pd, pe) - REAL *pa; - REAL *pb; - REAL *pc; - REAL *pd; - REAL *pe; -{ - INEXACT REAL aex, bex, cex, dex, aey, bey, cey, dey, aez, bez, cez, dez; - REAL aextail, bextail, cextail, dextail; - REAL aeytail, beytail, ceytail, deytail; - REAL aeztail, beztail, ceztail, deztail; - REAL negate, negatetail; - INEXACT REAL axby7, bxcy7, cxdy7, dxay7, axcy7, bxdy7; - INEXACT REAL bxay7, cxby7, dxcy7, axdy7, cxay7, dxby7; - REAL axby[8], bxcy[8], cxdy[8], dxay[8], axcy[8], bxdy[8]; - REAL bxay[8], cxby[8], dxcy[8], axdy[8], cxay[8], dxby[8]; - REAL ab[16], bc[16], cd[16], da[16], ac[16], bd[16]; - int ablen, bclen, cdlen, dalen, aclen, bdlen; - REAL temp32a[32], temp32b[32], temp64a[64], temp64b[64], temp64c[64]; - int temp32alen, temp32blen, temp64alen, temp64blen, temp64clen; - REAL temp128[128], temp192[192]; - int temp128len, temp192len; - REAL detx[384], detxx[768], detxt[384], detxxt[768], detxtxt[768]; - int xlen, xxlen, xtlen, xxtlen, xtxtlen; - REAL x1[1536], x2[2304]; - int x1len, x2len; - REAL dety[384], detyy[768], detyt[384], detyyt[768], detytyt[768]; - int ylen, yylen, ytlen, yytlen, ytytlen; - REAL y1[1536], y2[2304]; - int y1len, y2len; - REAL detz[384], detzz[768], detzt[384], detzzt[768], detztzt[768]; - int zlen, zzlen, ztlen, zztlen, ztztlen; - REAL z1[1536], z2[2304]; - int z1len, z2len; - REAL detxy[4608]; - int xylen; - REAL adet[6912], bdet[6912], cdet[6912], ddet[6912]; - int alen, blen, clen, dlen; - REAL abdet[13824], cddet[13824], deter[27648]; - int deterlen; - int i; - - INEXACT REAL bvirt; - REAL avirt, bround, around; - INEXACT REAL c; - INEXACT REAL abig; - REAL a0hi, a0lo, a1hi, a1lo, bhi, blo; - REAL err1, err2, err3; - INEXACT REAL _i, _j, _k, _l, _m, _n; - REAL _0, _1, _2; - - Two_Diff(pa[0], pe[0], aex, aextail); - Two_Diff(pa[1], pe[1], aey, aeytail); - Two_Diff(pa[2], pe[2], aez, aeztail); - Two_Diff(pb[0], pe[0], bex, bextail); - Two_Diff(pb[1], pe[1], bey, beytail); - Two_Diff(pb[2], pe[2], bez, beztail); - Two_Diff(pc[0], pe[0], cex, cextail); - Two_Diff(pc[1], pe[1], cey, ceytail); - Two_Diff(pc[2], pe[2], cez, ceztail); - Two_Diff(pd[0], pe[0], dex, dextail); - Two_Diff(pd[1], pe[1], dey, deytail); - Two_Diff(pd[2], pe[2], dez, deztail); - - Two_Two_Product(aex, aextail, bey, beytail, - axby7, axby[6], axby[5], axby[4], - axby[3], axby[2], axby[1], axby[0]); - axby[7] = axby7; - negate = -aey; - negatetail = -aeytail; - Two_Two_Product(bex, bextail, negate, negatetail, - bxay7, bxay[6], bxay[5], bxay[4], - bxay[3], bxay[2], bxay[1], bxay[0]); - bxay[7] = bxay7; - ablen = fast_expansion_sum_zeroelim(8, axby, 8, bxay, ab); - Two_Two_Product(bex, bextail, cey, ceytail, - bxcy7, bxcy[6], bxcy[5], bxcy[4], - bxcy[3], bxcy[2], bxcy[1], bxcy[0]); - bxcy[7] = bxcy7; - negate = -bey; - negatetail = -beytail; - Two_Two_Product(cex, cextail, negate, negatetail, - cxby7, cxby[6], cxby[5], cxby[4], - cxby[3], cxby[2], cxby[1], cxby[0]); - cxby[7] = cxby7; - bclen = fast_expansion_sum_zeroelim(8, bxcy, 8, cxby, bc); - Two_Two_Product(cex, cextail, dey, deytail, - cxdy7, cxdy[6], cxdy[5], cxdy[4], - cxdy[3], cxdy[2], cxdy[1], cxdy[0]); - cxdy[7] = cxdy7; - negate = -cey; - negatetail = -ceytail; - Two_Two_Product(dex, dextail, negate, negatetail, - dxcy7, dxcy[6], dxcy[5], dxcy[4], - dxcy[3], dxcy[2], dxcy[1], dxcy[0]); - dxcy[7] = dxcy7; - cdlen = fast_expansion_sum_zeroelim(8, cxdy, 8, dxcy, cd); - Two_Two_Product(dex, dextail, aey, aeytail, - dxay7, dxay[6], dxay[5], dxay[4], - dxay[3], dxay[2], dxay[1], dxay[0]); - dxay[7] = dxay7; - negate = -dey; - negatetail = -deytail; - Two_Two_Product(aex, aextail, negate, negatetail, - axdy7, axdy[6], axdy[5], axdy[4], - axdy[3], axdy[2], axdy[1], axdy[0]); - axdy[7] = axdy7; - dalen = fast_expansion_sum_zeroelim(8, dxay, 8, axdy, da); - Two_Two_Product(aex, aextail, cey, ceytail, - axcy7, axcy[6], axcy[5], axcy[4], - axcy[3], axcy[2], axcy[1], axcy[0]); - axcy[7] = axcy7; - negate = -aey; - negatetail = -aeytail; - Two_Two_Product(cex, cextail, negate, negatetail, - cxay7, cxay[6], cxay[5], cxay[4], - cxay[3], cxay[2], cxay[1], cxay[0]); - cxay[7] = cxay7; - aclen = fast_expansion_sum_zeroelim(8, axcy, 8, cxay, ac); - Two_Two_Product(bex, bextail, dey, deytail, - bxdy7, bxdy[6], bxdy[5], bxdy[4], - bxdy[3], bxdy[2], bxdy[1], bxdy[0]); - bxdy[7] = bxdy7; - negate = -bey; - negatetail = -beytail; - Two_Two_Product(dex, dextail, negate, negatetail, - dxby7, dxby[6], dxby[5], dxby[4], - dxby[3], dxby[2], dxby[1], dxby[0]); - dxby[7] = dxby7; - bdlen = fast_expansion_sum_zeroelim(8, bxdy, 8, dxby, bd); - - temp32alen = scale_expansion_zeroelim(cdlen, cd, -bez, temp32a); - temp32blen = scale_expansion_zeroelim(cdlen, cd, -beztail, temp32b); - temp64alen = fast_expansion_sum_zeroelim(temp32alen, temp32a, - temp32blen, temp32b, temp64a); - temp32alen = scale_expansion_zeroelim(bdlen, bd, cez, temp32a); - temp32blen = scale_expansion_zeroelim(bdlen, bd, ceztail, temp32b); - temp64blen = fast_expansion_sum_zeroelim(temp32alen, temp32a, - temp32blen, temp32b, temp64b); - temp32alen = scale_expansion_zeroelim(bclen, bc, -dez, temp32a); - temp32blen = scale_expansion_zeroelim(bclen, bc, -deztail, temp32b); - temp64clen = fast_expansion_sum_zeroelim(temp32alen, temp32a, - temp32blen, temp32b, temp64c); - temp128len = fast_expansion_sum_zeroelim(temp64alen, temp64a, - temp64blen, temp64b, temp128); - temp192len = fast_expansion_sum_zeroelim(temp64clen, temp64c, - temp128len, temp128, temp192); - xlen = scale_expansion_zeroelim(temp192len, temp192, aex, detx); - xxlen = scale_expansion_zeroelim(xlen, detx, aex, detxx); - xtlen = scale_expansion_zeroelim(temp192len, temp192, aextail, detxt); - xxtlen = scale_expansion_zeroelim(xtlen, detxt, aex, detxxt); - for (i = 0; i < xxtlen; i++) { - detxxt[i] *= 2.0; - } - xtxtlen = scale_expansion_zeroelim(xtlen, detxt, aextail, detxtxt); - x1len = fast_expansion_sum_zeroelim(xxlen, detxx, xxtlen, detxxt, x1); - x2len = fast_expansion_sum_zeroelim(x1len, x1, xtxtlen, detxtxt, x2); - ylen = scale_expansion_zeroelim(temp192len, temp192, aey, dety); - yylen = scale_expansion_zeroelim(ylen, dety, aey, detyy); - ytlen = scale_expansion_zeroelim(temp192len, temp192, aeytail, detyt); - yytlen = scale_expansion_zeroelim(ytlen, detyt, aey, detyyt); - for (i = 0; i < yytlen; i++) { - detyyt[i] *= 2.0; - } - ytytlen = scale_expansion_zeroelim(ytlen, detyt, aeytail, detytyt); - y1len = fast_expansion_sum_zeroelim(yylen, detyy, yytlen, detyyt, y1); - y2len = fast_expansion_sum_zeroelim(y1len, y1, ytytlen, detytyt, y2); - zlen = scale_expansion_zeroelim(temp192len, temp192, aez, detz); - zzlen = scale_expansion_zeroelim(zlen, detz, aez, detzz); - ztlen = scale_expansion_zeroelim(temp192len, temp192, aeztail, detzt); - zztlen = scale_expansion_zeroelim(ztlen, detzt, aez, detzzt); - for (i = 0; i < zztlen; i++) { - detzzt[i] *= 2.0; - } - ztztlen = scale_expansion_zeroelim(ztlen, detzt, aeztail, detztzt); - z1len = fast_expansion_sum_zeroelim(zzlen, detzz, zztlen, detzzt, z1); - z2len = fast_expansion_sum_zeroelim(z1len, z1, ztztlen, detztzt, z2); - xylen = fast_expansion_sum_zeroelim(x2len, x2, y2len, y2, detxy); - alen = fast_expansion_sum_zeroelim(z2len, z2, xylen, detxy, adet); - - temp32alen = scale_expansion_zeroelim(dalen, da, cez, temp32a); - temp32blen = scale_expansion_zeroelim(dalen, da, ceztail, temp32b); - temp64alen = fast_expansion_sum_zeroelim(temp32alen, temp32a, - temp32blen, temp32b, temp64a); - temp32alen = scale_expansion_zeroelim(aclen, ac, dez, temp32a); - temp32blen = scale_expansion_zeroelim(aclen, ac, deztail, temp32b); - temp64blen = fast_expansion_sum_zeroelim(temp32alen, temp32a, - temp32blen, temp32b, temp64b); - temp32alen = scale_expansion_zeroelim(cdlen, cd, aez, temp32a); - temp32blen = scale_expansion_zeroelim(cdlen, cd, aeztail, temp32b); - temp64clen = fast_expansion_sum_zeroelim(temp32alen, temp32a, - temp32blen, temp32b, temp64c); - temp128len = fast_expansion_sum_zeroelim(temp64alen, temp64a, - temp64blen, temp64b, temp128); - temp192len = fast_expansion_sum_zeroelim(temp64clen, temp64c, - temp128len, temp128, temp192); - xlen = scale_expansion_zeroelim(temp192len, temp192, bex, detx); - xxlen = scale_expansion_zeroelim(xlen, detx, bex, detxx); - xtlen = scale_expansion_zeroelim(temp192len, temp192, bextail, detxt); - xxtlen = scale_expansion_zeroelim(xtlen, detxt, bex, detxxt); - for (i = 0; i < xxtlen; i++) { - detxxt[i] *= 2.0; - } - xtxtlen = scale_expansion_zeroelim(xtlen, detxt, bextail, detxtxt); - x1len = fast_expansion_sum_zeroelim(xxlen, detxx, xxtlen, detxxt, x1); - x2len = fast_expansion_sum_zeroelim(x1len, x1, xtxtlen, detxtxt, x2); - ylen = scale_expansion_zeroelim(temp192len, temp192, bey, dety); - yylen = scale_expansion_zeroelim(ylen, dety, bey, detyy); - ytlen = scale_expansion_zeroelim(temp192len, temp192, beytail, detyt); - yytlen = scale_expansion_zeroelim(ytlen, detyt, bey, detyyt); - for (i = 0; i < yytlen; i++) { - detyyt[i] *= 2.0; - } - ytytlen = scale_expansion_zeroelim(ytlen, detyt, beytail, detytyt); - y1len = fast_expansion_sum_zeroelim(yylen, detyy, yytlen, detyyt, y1); - y2len = fast_expansion_sum_zeroelim(y1len, y1, ytytlen, detytyt, y2); - zlen = scale_expansion_zeroelim(temp192len, temp192, bez, detz); - zzlen = scale_expansion_zeroelim(zlen, detz, bez, detzz); - ztlen = scale_expansion_zeroelim(temp192len, temp192, beztail, detzt); - zztlen = scale_expansion_zeroelim(ztlen, detzt, bez, detzzt); - for (i = 0; i < zztlen; i++) { - detzzt[i] *= 2.0; - } - ztztlen = scale_expansion_zeroelim(ztlen, detzt, beztail, detztzt); - z1len = fast_expansion_sum_zeroelim(zzlen, detzz, zztlen, detzzt, z1); - z2len = fast_expansion_sum_zeroelim(z1len, z1, ztztlen, detztzt, z2); - xylen = fast_expansion_sum_zeroelim(x2len, x2, y2len, y2, detxy); - blen = fast_expansion_sum_zeroelim(z2len, z2, xylen, detxy, bdet); - - temp32alen = scale_expansion_zeroelim(ablen, ab, -dez, temp32a); - temp32blen = scale_expansion_zeroelim(ablen, ab, -deztail, temp32b); - temp64alen = fast_expansion_sum_zeroelim(temp32alen, temp32a, - temp32blen, temp32b, temp64a); - temp32alen = scale_expansion_zeroelim(bdlen, bd, -aez, temp32a); - temp32blen = scale_expansion_zeroelim(bdlen, bd, -aeztail, temp32b); - temp64blen = fast_expansion_sum_zeroelim(temp32alen, temp32a, - temp32blen, temp32b, temp64b); - temp32alen = scale_expansion_zeroelim(dalen, da, -bez, temp32a); - temp32blen = scale_expansion_zeroelim(dalen, da, -beztail, temp32b); - temp64clen = fast_expansion_sum_zeroelim(temp32alen, temp32a, - temp32blen, temp32b, temp64c); - temp128len = fast_expansion_sum_zeroelim(temp64alen, temp64a, - temp64blen, temp64b, temp128); - temp192len = fast_expansion_sum_zeroelim(temp64clen, temp64c, - temp128len, temp128, temp192); - xlen = scale_expansion_zeroelim(temp192len, temp192, cex, detx); - xxlen = scale_expansion_zeroelim(xlen, detx, cex, detxx); - xtlen = scale_expansion_zeroelim(temp192len, temp192, cextail, detxt); - xxtlen = scale_expansion_zeroelim(xtlen, detxt, cex, detxxt); - for (i = 0; i < xxtlen; i++) { - detxxt[i] *= 2.0; - } - xtxtlen = scale_expansion_zeroelim(xtlen, detxt, cextail, detxtxt); - x1len = fast_expansion_sum_zeroelim(xxlen, detxx, xxtlen, detxxt, x1); - x2len = fast_expansion_sum_zeroelim(x1len, x1, xtxtlen, detxtxt, x2); - ylen = scale_expansion_zeroelim(temp192len, temp192, cey, dety); - yylen = scale_expansion_zeroelim(ylen, dety, cey, detyy); - ytlen = scale_expansion_zeroelim(temp192len, temp192, ceytail, detyt); - yytlen = scale_expansion_zeroelim(ytlen, detyt, cey, detyyt); - for (i = 0; i < yytlen; i++) { - detyyt[i] *= 2.0; - } - ytytlen = scale_expansion_zeroelim(ytlen, detyt, ceytail, detytyt); - y1len = fast_expansion_sum_zeroelim(yylen, detyy, yytlen, detyyt, y1); - y2len = fast_expansion_sum_zeroelim(y1len, y1, ytytlen, detytyt, y2); - zlen = scale_expansion_zeroelim(temp192len, temp192, cez, detz); - zzlen = scale_expansion_zeroelim(zlen, detz, cez, detzz); - ztlen = scale_expansion_zeroelim(temp192len, temp192, ceztail, detzt); - zztlen = scale_expansion_zeroelim(ztlen, detzt, cez, detzzt); - for (i = 0; i < zztlen; i++) { - detzzt[i] *= 2.0; - } - ztztlen = scale_expansion_zeroelim(ztlen, detzt, ceztail, detztzt); - z1len = fast_expansion_sum_zeroelim(zzlen, detzz, zztlen, detzzt, z1); - z2len = fast_expansion_sum_zeroelim(z1len, z1, ztztlen, detztzt, z2); - xylen = fast_expansion_sum_zeroelim(x2len, x2, y2len, y2, detxy); - clen = fast_expansion_sum_zeroelim(z2len, z2, xylen, detxy, cdet); - - temp32alen = scale_expansion_zeroelim(bclen, bc, aez, temp32a); - temp32blen = scale_expansion_zeroelim(bclen, bc, aeztail, temp32b); - temp64alen = fast_expansion_sum_zeroelim(temp32alen, temp32a, - temp32blen, temp32b, temp64a); - temp32alen = scale_expansion_zeroelim(aclen, ac, -bez, temp32a); - temp32blen = scale_expansion_zeroelim(aclen, ac, -beztail, temp32b); - temp64blen = fast_expansion_sum_zeroelim(temp32alen, temp32a, - temp32blen, temp32b, temp64b); - temp32alen = scale_expansion_zeroelim(ablen, ab, cez, temp32a); - temp32blen = scale_expansion_zeroelim(ablen, ab, ceztail, temp32b); - temp64clen = fast_expansion_sum_zeroelim(temp32alen, temp32a, - temp32blen, temp32b, temp64c); - temp128len = fast_expansion_sum_zeroelim(temp64alen, temp64a, - temp64blen, temp64b, temp128); - temp192len = fast_expansion_sum_zeroelim(temp64clen, temp64c, - temp128len, temp128, temp192); - xlen = scale_expansion_zeroelim(temp192len, temp192, dex, detx); - xxlen = scale_expansion_zeroelim(xlen, detx, dex, detxx); - xtlen = scale_expansion_zeroelim(temp192len, temp192, dextail, detxt); - xxtlen = scale_expansion_zeroelim(xtlen, detxt, dex, detxxt); - for (i = 0; i < xxtlen; i++) { - detxxt[i] *= 2.0; - } - xtxtlen = scale_expansion_zeroelim(xtlen, detxt, dextail, detxtxt); - x1len = fast_expansion_sum_zeroelim(xxlen, detxx, xxtlen, detxxt, x1); - x2len = fast_expansion_sum_zeroelim(x1len, x1, xtxtlen, detxtxt, x2); - ylen = scale_expansion_zeroelim(temp192len, temp192, dey, dety); - yylen = scale_expansion_zeroelim(ylen, dety, dey, detyy); - ytlen = scale_expansion_zeroelim(temp192len, temp192, deytail, detyt); - yytlen = scale_expansion_zeroelim(ytlen, detyt, dey, detyyt); - for (i = 0; i < yytlen; i++) { - detyyt[i] *= 2.0; - } - ytytlen = scale_expansion_zeroelim(ytlen, detyt, deytail, detytyt); - y1len = fast_expansion_sum_zeroelim(yylen, detyy, yytlen, detyyt, y1); - y2len = fast_expansion_sum_zeroelim(y1len, y1, ytytlen, detytyt, y2); - zlen = scale_expansion_zeroelim(temp192len, temp192, dez, detz); - zzlen = scale_expansion_zeroelim(zlen, detz, dez, detzz); - ztlen = scale_expansion_zeroelim(temp192len, temp192, deztail, detzt); - zztlen = scale_expansion_zeroelim(ztlen, detzt, dez, detzzt); - for (i = 0; i < zztlen; i++) { - detzzt[i] *= 2.0; - } - ztztlen = scale_expansion_zeroelim(ztlen, detzt, deztail, detztzt); - z1len = fast_expansion_sum_zeroelim(zzlen, detzz, zztlen, detzzt, z1); - z2len = fast_expansion_sum_zeroelim(z1len, z1, ztztlen, detztzt, z2); - xylen = fast_expansion_sum_zeroelim(x2len, x2, y2len, y2, detxy); - dlen = fast_expansion_sum_zeroelim(z2len, z2, xylen, detxy, ddet); - - ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet); - cdlen = fast_expansion_sum_zeroelim(clen, cdet, dlen, ddet, cddet); - deterlen = fast_expansion_sum_zeroelim(ablen, abdet, cdlen, cddet, deter); - - return deter[deterlen - 1]; -} - -REAL insphereadapt(pa, pb, pc, pd, pe, permanent) - REAL *pa; - REAL *pb; - REAL *pc; - REAL *pd; - REAL *pe; - REAL permanent; -{ - INEXACT REAL aex, bex, cex, dex, aey, bey, cey, dey, aez, bez, cez, dez; - REAL det, errbound; - - INEXACT REAL aexbey1, bexaey1, bexcey1, cexbey1; - INEXACT REAL cexdey1, dexcey1, dexaey1, aexdey1; - INEXACT REAL aexcey1, cexaey1, bexdey1, dexbey1; - REAL aexbey0, bexaey0, bexcey0, cexbey0; - REAL cexdey0, dexcey0, dexaey0, aexdey0; - REAL aexcey0, cexaey0, bexdey0, dexbey0; - REAL ab[4], bc[4], cd[4], da[4], ac[4], bd[4]; - INEXACT REAL ab3, bc3, cd3, da3, ac3, bd3; - REAL abeps, bceps, cdeps, daeps, aceps, bdeps; - REAL temp8a[8], temp8b[8], temp8c[8], temp16[16], temp24[24], temp48[48]; - int temp8alen, temp8blen, temp8clen, temp16len, temp24len, temp48len; - REAL xdet[96], ydet[96], zdet[96], xydet[192]; - int xlen, ylen, zlen, xylen; - REAL adet[288], bdet[288], cdet[288], ddet[288]; - int alen, blen, clen, dlen; - REAL abdet[576], cddet[576]; - int ablen, cdlen; - REAL fin1[1152]; - int finlength; - - REAL aextail, bextail, cextail, dextail; - REAL aeytail, beytail, ceytail, deytail; - REAL aeztail, beztail, ceztail, deztail; - - INEXACT REAL bvirt; - REAL avirt, bround, around; - INEXACT REAL c; - INEXACT REAL abig; - REAL ahi, alo, bhi, blo; - REAL err1, err2, err3; - INEXACT REAL _i, _j; - REAL _0; - - aex = (REAL) (pa[0] - pe[0]); - bex = (REAL) (pb[0] - pe[0]); - cex = (REAL) (pc[0] - pe[0]); - dex = (REAL) (pd[0] - pe[0]); - aey = (REAL) (pa[1] - pe[1]); - bey = (REAL) (pb[1] - pe[1]); - cey = (REAL) (pc[1] - pe[1]); - dey = (REAL) (pd[1] - pe[1]); - aez = (REAL) (pa[2] - pe[2]); - bez = (REAL) (pb[2] - pe[2]); - cez = (REAL) (pc[2] - pe[2]); - dez = (REAL) (pd[2] - pe[2]); - - Two_Product(aex, bey, aexbey1, aexbey0); - Two_Product(bex, aey, bexaey1, bexaey0); - Two_Two_Diff(aexbey1, aexbey0, bexaey1, bexaey0, ab3, ab[2], ab[1], ab[0]); - ab[3] = ab3; - - Two_Product(bex, cey, bexcey1, bexcey0); - Two_Product(cex, bey, cexbey1, cexbey0); - Two_Two_Diff(bexcey1, bexcey0, cexbey1, cexbey0, bc3, bc[2], bc[1], bc[0]); - bc[3] = bc3; - - Two_Product(cex, dey, cexdey1, cexdey0); - Two_Product(dex, cey, dexcey1, dexcey0); - Two_Two_Diff(cexdey1, cexdey0, dexcey1, dexcey0, cd3, cd[2], cd[1], cd[0]); - cd[3] = cd3; - - Two_Product(dex, aey, dexaey1, dexaey0); - Two_Product(aex, dey, aexdey1, aexdey0); - Two_Two_Diff(dexaey1, dexaey0, aexdey1, aexdey0, da3, da[2], da[1], da[0]); - da[3] = da3; - - Two_Product(aex, cey, aexcey1, aexcey0); - Two_Product(cex, aey, cexaey1, cexaey0); - Two_Two_Diff(aexcey1, aexcey0, cexaey1, cexaey0, ac3, ac[2], ac[1], ac[0]); - ac[3] = ac3; - - Two_Product(bex, dey, bexdey1, bexdey0); - Two_Product(dex, bey, dexbey1, dexbey0); - Two_Two_Diff(bexdey1, bexdey0, dexbey1, dexbey0, bd3, bd[2], bd[1], bd[0]); - bd[3] = bd3; - - temp8alen = scale_expansion_zeroelim(4, cd, bez, temp8a); - temp8blen = scale_expansion_zeroelim(4, bd, -cez, temp8b); - temp8clen = scale_expansion_zeroelim(4, bc, dez, temp8c); - temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, - temp8blen, temp8b, temp16); - temp24len = fast_expansion_sum_zeroelim(temp8clen, temp8c, - temp16len, temp16, temp24); - temp48len = scale_expansion_zeroelim(temp24len, temp24, aex, temp48); - xlen = scale_expansion_zeroelim(temp48len, temp48, -aex, xdet); - temp48len = scale_expansion_zeroelim(temp24len, temp24, aey, temp48); - ylen = scale_expansion_zeroelim(temp48len, temp48, -aey, ydet); - temp48len = scale_expansion_zeroelim(temp24len, temp24, aez, temp48); - zlen = scale_expansion_zeroelim(temp48len, temp48, -aez, zdet); - xylen = fast_expansion_sum_zeroelim(xlen, xdet, ylen, ydet, xydet); - alen = fast_expansion_sum_zeroelim(xylen, xydet, zlen, zdet, adet); - - temp8alen = scale_expansion_zeroelim(4, da, cez, temp8a); - temp8blen = scale_expansion_zeroelim(4, ac, dez, temp8b); - temp8clen = scale_expansion_zeroelim(4, cd, aez, temp8c); - temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, - temp8blen, temp8b, temp16); - temp24len = fast_expansion_sum_zeroelim(temp8clen, temp8c, - temp16len, temp16, temp24); - temp48len = scale_expansion_zeroelim(temp24len, temp24, bex, temp48); - xlen = scale_expansion_zeroelim(temp48len, temp48, bex, xdet); - temp48len = scale_expansion_zeroelim(temp24len, temp24, bey, temp48); - ylen = scale_expansion_zeroelim(temp48len, temp48, bey, ydet); - temp48len = scale_expansion_zeroelim(temp24len, temp24, bez, temp48); - zlen = scale_expansion_zeroelim(temp48len, temp48, bez, zdet); - xylen = fast_expansion_sum_zeroelim(xlen, xdet, ylen, ydet, xydet); - blen = fast_expansion_sum_zeroelim(xylen, xydet, zlen, zdet, bdet); - - temp8alen = scale_expansion_zeroelim(4, ab, dez, temp8a); - temp8blen = scale_expansion_zeroelim(4, bd, aez, temp8b); - temp8clen = scale_expansion_zeroelim(4, da, bez, temp8c); - temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, - temp8blen, temp8b, temp16); - temp24len = fast_expansion_sum_zeroelim(temp8clen, temp8c, - temp16len, temp16, temp24); - temp48len = scale_expansion_zeroelim(temp24len, temp24, cex, temp48); - xlen = scale_expansion_zeroelim(temp48len, temp48, -cex, xdet); - temp48len = scale_expansion_zeroelim(temp24len, temp24, cey, temp48); - ylen = scale_expansion_zeroelim(temp48len, temp48, -cey, ydet); - temp48len = scale_expansion_zeroelim(temp24len, temp24, cez, temp48); - zlen = scale_expansion_zeroelim(temp48len, temp48, -cez, zdet); - xylen = fast_expansion_sum_zeroelim(xlen, xdet, ylen, ydet, xydet); - clen = fast_expansion_sum_zeroelim(xylen, xydet, zlen, zdet, cdet); - - temp8alen = scale_expansion_zeroelim(4, bc, aez, temp8a); - temp8blen = scale_expansion_zeroelim(4, ac, -bez, temp8b); - temp8clen = scale_expansion_zeroelim(4, ab, cez, temp8c); - temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, - temp8blen, temp8b, temp16); - temp24len = fast_expansion_sum_zeroelim(temp8clen, temp8c, - temp16len, temp16, temp24); - temp48len = scale_expansion_zeroelim(temp24len, temp24, dex, temp48); - xlen = scale_expansion_zeroelim(temp48len, temp48, dex, xdet); - temp48len = scale_expansion_zeroelim(temp24len, temp24, dey, temp48); - ylen = scale_expansion_zeroelim(temp48len, temp48, dey, ydet); - temp48len = scale_expansion_zeroelim(temp24len, temp24, dez, temp48); - zlen = scale_expansion_zeroelim(temp48len, temp48, dez, zdet); - xylen = fast_expansion_sum_zeroelim(xlen, xdet, ylen, ydet, xydet); - dlen = fast_expansion_sum_zeroelim(xylen, xydet, zlen, zdet, ddet); - - ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet); - cdlen = fast_expansion_sum_zeroelim(clen, cdet, dlen, ddet, cddet); - finlength = fast_expansion_sum_zeroelim(ablen, abdet, cdlen, cddet, fin1); - - det = estimate(finlength, fin1); - errbound = isperrboundB * permanent; - if ((det >= errbound) || (-det >= errbound)) { - return det; - } - - Two_Diff_Tail(pa[0], pe[0], aex, aextail); - Two_Diff_Tail(pa[1], pe[1], aey, aeytail); - Two_Diff_Tail(pa[2], pe[2], aez, aeztail); - Two_Diff_Tail(pb[0], pe[0], bex, bextail); - Two_Diff_Tail(pb[1], pe[1], bey, beytail); - Two_Diff_Tail(pb[2], pe[2], bez, beztail); - Two_Diff_Tail(pc[0], pe[0], cex, cextail); - Two_Diff_Tail(pc[1], pe[1], cey, ceytail); - Two_Diff_Tail(pc[2], pe[2], cez, ceztail); - Two_Diff_Tail(pd[0], pe[0], dex, dextail); - Two_Diff_Tail(pd[1], pe[1], dey, deytail); - Two_Diff_Tail(pd[2], pe[2], dez, deztail); - if ((aextail == 0.0) && (aeytail == 0.0) && (aeztail == 0.0) - && (bextail == 0.0) && (beytail == 0.0) && (beztail == 0.0) - && (cextail == 0.0) && (ceytail == 0.0) && (ceztail == 0.0) - && (dextail == 0.0) && (deytail == 0.0) && (deztail == 0.0)) { - return det; - } - - errbound = isperrboundC * permanent + resulterrbound * Absolute(det); - abeps = (aex * beytail + bey * aextail) - - (aey * bextail + bex * aeytail); - bceps = (bex * ceytail + cey * bextail) - - (bey * cextail + cex * beytail); - cdeps = (cex * deytail + dey * cextail) - - (cey * dextail + dex * ceytail); - daeps = (dex * aeytail + aey * dextail) - - (dey * aextail + aex * deytail); - aceps = (aex * ceytail + cey * aextail) - - (aey * cextail + cex * aeytail); - bdeps = (bex * deytail + dey * bextail) - - (bey * dextail + dex * beytail); - det += (((bex * bex + bey * bey + bez * bez) - * ((cez * daeps + dez * aceps + aez * cdeps) - + (ceztail * da3 + deztail * ac3 + aeztail * cd3)) - + (dex * dex + dey * dey + dez * dez) - * ((aez * bceps - bez * aceps + cez * abeps) - + (aeztail * bc3 - beztail * ac3 + ceztail * ab3))) - - ((aex * aex + aey * aey + aez * aez) - * ((bez * cdeps - cez * bdeps + dez * bceps) - + (beztail * cd3 - ceztail * bd3 + deztail * bc3)) - + (cex * cex + cey * cey + cez * cez) - * ((dez * abeps + aez * bdeps + bez * daeps) - + (deztail * ab3 + aeztail * bd3 + beztail * da3)))) - + 2.0 * (((bex * bextail + bey * beytail + bez * beztail) - * (cez * da3 + dez * ac3 + aez * cd3) - + (dex * dextail + dey * deytail + dez * deztail) - * (aez * bc3 - bez * ac3 + cez * ab3)) - - ((aex * aextail + aey * aeytail + aez * aeztail) - * (bez * cd3 - cez * bd3 + dez * bc3) - + (cex * cextail + cey * ceytail + cez * ceztail) - * (dez * ab3 + aez * bd3 + bez * da3))); - if ((det >= errbound) || (-det >= errbound)) { - return det; - } - - return insphereexact(pa, pb, pc, pd, pe); -} - -REAL insphere(pa, pb, pc, pd, pe) - REAL *pa; - REAL *pb; - REAL *pc; - REAL *pd; - REAL *pe; -{ - REAL aex, bex, cex, dex; - REAL aey, bey, cey, dey; - REAL aez, bez, cez, dez; - REAL aexbey, bexaey, bexcey, cexbey, cexdey, dexcey, dexaey, aexdey; - REAL aexcey, cexaey, bexdey, dexbey; - REAL alift, blift, clift, dlift; - REAL ab, bc, cd, da, ac, bd; - REAL abc, bcd, cda, dab; - REAL aezplus, bezplus, cezplus, dezplus; - REAL aexbeyplus, bexaeyplus, bexceyplus, cexbeyplus; - REAL cexdeyplus, dexceyplus, dexaeyplus, aexdeyplus; - REAL aexceyplus, cexaeyplus, bexdeyplus, dexbeyplus; - REAL det; - REAL permanent, errbound; - - aex = pa[0] - pe[0]; - bex = pb[0] - pe[0]; - cex = pc[0] - pe[0]; - dex = pd[0] - pe[0]; - aey = pa[1] - pe[1]; - bey = pb[1] - pe[1]; - cey = pc[1] - pe[1]; - dey = pd[1] - pe[1]; - aez = pa[2] - pe[2]; - bez = pb[2] - pe[2]; - cez = pc[2] - pe[2]; - dez = pd[2] - pe[2]; - - aexbey = aex * bey; - bexaey = bex * aey; - ab = aexbey - bexaey; - bexcey = bex * cey; - cexbey = cex * bey; - bc = bexcey - cexbey; - cexdey = cex * dey; - dexcey = dex * cey; - cd = cexdey - dexcey; - dexaey = dex * aey; - aexdey = aex * dey; - da = dexaey - aexdey; - - aexcey = aex * cey; - cexaey = cex * aey; - ac = aexcey - cexaey; - bexdey = bex * dey; - dexbey = dex * bey; - bd = bexdey - dexbey; - - abc = aez * bc - bez * ac + cez * ab; - bcd = bez * cd - cez * bd + dez * bc; - cda = cez * da + dez * ac + aez * cd; - dab = dez * ab + aez * bd + bez * da; - - alift = aex * aex + aey * aey + aez * aez; - blift = bex * bex + bey * bey + bez * bez; - clift = cex * cex + cey * cey + cez * cez; - dlift = dex * dex + dey * dey + dez * dez; - - det = (dlift * abc - clift * dab) + (blift * cda - alift * bcd); - - aezplus = Absolute(aez); - bezplus = Absolute(bez); - cezplus = Absolute(cez); - dezplus = Absolute(dez); - aexbeyplus = Absolute(aexbey); - bexaeyplus = Absolute(bexaey); - bexceyplus = Absolute(bexcey); - cexbeyplus = Absolute(cexbey); - cexdeyplus = Absolute(cexdey); - dexceyplus = Absolute(dexcey); - dexaeyplus = Absolute(dexaey); - aexdeyplus = Absolute(aexdey); - aexceyplus = Absolute(aexcey); - cexaeyplus = Absolute(cexaey); - bexdeyplus = Absolute(bexdey); - dexbeyplus = Absolute(dexbey); - permanent = ((cexdeyplus + dexceyplus) * bezplus - + (dexbeyplus + bexdeyplus) * cezplus - + (bexceyplus + cexbeyplus) * dezplus) - * alift - + ((dexaeyplus + aexdeyplus) * cezplus - + (aexceyplus + cexaeyplus) * dezplus - + (cexdeyplus + dexceyplus) * aezplus) - * blift - + ((aexbeyplus + bexaeyplus) * dezplus - + (bexdeyplus + dexbeyplus) * aezplus - + (dexaeyplus + aexdeyplus) * bezplus) - * clift - + ((bexceyplus + cexbeyplus) * aezplus - + (cexaeyplus + aexceyplus) * bezplus - + (aexbeyplus + bexaeyplus) * cezplus) - * dlift; - errbound = isperrboundA * permanent; - if ((det > errbound) || (-det > errbound)) { - return det; - } - - return insphereadapt(pa, pb, pc, pd, pe, permanent); -} \ No newline at end of file diff --git a/lib/ext/predicates.h b/lib/ext/predicates.h deleted file mode 100644 index 95bedae..0000000 --- a/lib/ext/predicates.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * - * ##### # # # * - * #### ##### ###### # # # # # # # * - * # # # # # ## # # # # # * - * # # # # ##### # # # # #### # ### * - * # # ##### # # # # # # # # # # * - * # # # # # ## # # # # # # * - * #### # ###### # # ##### ##### # # * - * * - * This file is part of openGJK. * - * * - * openGJK is free software: you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation, either version 3 of the License, or * - * any later version. * - * * - * openGJK is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See The * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with Foobar. If not, see . * - * * - * openGJK: open-source Gilbert-Johnson-Keerthi algorithm * - * Copyright (C) Mattia Montanari 2018 - 2019 * - * http://iel.eng.ox.ac.uk/?page_id=504 * - * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - -#include -#include - -#ifndef CGJK_PREDICATES_H -#define CGJK_PREDICATES_H - -#endif //CGJK_PREDICATES_H - -extern double orient3d( - double *pa, - double *pb, - double *pc, - double *pd -); - -extern double orient2d( - double *pa, - double *pb, - double *pc -); - -extern void exactinit(); diff --git a/lib/include/openGJK/openGJK.h b/lib/include/openGJK/openGJK.h deleted file mode 100644 index 6d96ef6..0000000 --- a/lib/include/openGJK/openGJK.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * - * ##### # # # * - * #### ##### ###### # # # # # # # * - * # # # # # ## # # # # # * - * # # # # ##### # # # # #### # ### * - * # # ##### # # # # # # # # # # * - * # # # # # ## # # # # # # * - * #### # ###### # # ##### ##### # # * - * * - * This file is part of openGJK. * - * * - * openGJK is free software: you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation, either version 3 of the License, or * - * any later version. * - * * - * openGJK is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See The * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with Foobar. If not, see . * - * * - * openGJK: open-source Gilbert-Johnson-Keerthi algorithm * - * Copyright (C) Mattia Montanari 2018 - 2019 * - * http://iel.eng.ox.ac.uk/?page_id=504 * - * * - * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * - * * - * This is the header file for the openGJK.c file. It defines the * - * openGJK function and its structures. * - * * - * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - -#ifndef __OPENGJK_H__ -#define __OPENGJK_H__ - -#include -#include -#include "math.h" - - -/** - * @brief Macro that implements the CompareSign function (see paper). - */ - #define SAMESIGN( a, b ) ( (a>0) == (b>0) ) - - -/** - * @brief Structure of a body. - */ -struct bd { - int numpoints; /**< Number of points defining the body. */ - double **coord; /**< Pointer to pointer to the points' coordinates. */ - double s [3]; /**< Support mapping computed last. */ -}; - - - - -/** - * @brief Structure for a simplex. - */ -struct simplex { - int nvrtx ; /**< Number of simplex's vertices. */ - double vrtx [4][3]; /**< Coordinates of simplex's vertices. */ - int wids [4]; /**< Label of the simplex's vertices. */ - double lambdas [4]; /**< Barycentric coordiantes for each vertex. */ - double p [4][3]; /**< Points of P that form the simplex */ - double q [4][3]; /**< Points of Q that form the simplex */ -}; - - - - -/** - * @brief The GJK algorithm which returns the minimum distance between - * two bodies. - */ -extern double gjk( struct bd, struct bd, struct simplex * ) ; - -#endif \ No newline at end of file diff --git a/lib/src/openGJK.c b/lib/src/openGJK.c deleted file mode 100644 index 18d383e..0000000 --- a/lib/src/openGJK.c +++ /dev/null @@ -1,1009 +0,0 @@ -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * - * ##### # # # * - * #### ##### ###### # # # # # # # * - * # # # # # ## # # # # # * - * # # # # ##### # # # # #### # ### * - * # # ##### # # # # # # # # # # * - * # # # # # ## # # # # # # * - * #### # ###### # # ##### ##### # # * - * * - * This file is part of openGJK. * - * * - * openGJK is free software: you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation, either version 3 of the License, or * - * any later version. * - * * - * openGJK is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See The * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with Foobar. If not, see . * - * * - * openGJK: open-source Gilbert-Johnson-Keerthi algorithm * - * Copyright (C) Mattia Montanari 2018 - 2019 * - * http://iel.eng.ox.ac.uk/?page_id=504 * - * * - * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * - * * - * This file implements the GJK algorithm and the Signed Volumes method as* - * presented in: * - * M. Montanari, N. Petrinic, E. Barbieri, "Improving the GJK Algorithm * - * for Faster and More Reliable Distance Queries Between Convex Objects"* - * ACM Transactions on Graphics, vol. 36, no. 3, Jun. 2017. * - * * - * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - -/** - * @file openGJK.c - * @author Mattia Montanari - * @date April 2018 - * @brief File containing entire implementation of the GJK algorithm. - * - */ - -#define _CRT_HAS_CXX17 0 -#include -#include "openGJK/openGJK.h" - -/* If instricuted, uses adaptive floating point arithmetics. */ -#ifdef ADAPTIVEFP -#include "predicates.h" -#endif - -/* If instricuted, compile a mex function for Matlab. */ -#ifdef MATLABDOESMEXSTUFF - #include "mex.h" -#else - #define mexPrintf printf -#endif - -#ifdef unix - #define _isnan(x) isnan(x) -#endif - -#define dotProduct(a, b) (a[0]*b[0]+a[1]*b[1]+a[2]*b[2]) - -/** - * @brief Returns squared vector norm - */ -double norm2(double *v) { - double n2 = 0; - for (int i = 0; i < 3; ++i) - n2 += v[i] * v[i]; - return n2; -} - -/** - * @brief Finds point of minimum norm of 1-simplex. Robust, but slower, version of algorithm presented in paper. - */ -inline static void S1D(struct simplex * s, double *vv) { - int i = 0; - int indexI = 1; - int FacetsTest[2]; - double det_ap = 0; - double det_pb = 0; - double pt = 0; - double leng = 0; - double a[3]; - double b[3]; - double t[3]; - double nu_fabs[3]; - - for (i = 0; i < 3; ++i) { - b[i] = s->vrtx[0][i]; - a[i] = s->vrtx[1][i]; - t[i] = b[i] - a[i]; - leng += t[i]; - nu_fabs[i] = fabs(t[i]); - } - - if (nu_fabs[0] > nu_fabs[1]) { - if (nu_fabs[0] > nu_fabs[2]) - indexI = 0; - else - indexI = 2; - } - else if (nu_fabs[0] < nu_fabs[1]) { - if (nu_fabs[1] > nu_fabs[2]) - indexI = 1; - else - indexI = 2; - } - else if (nu_fabs[0] < nu_fabs[2]) { - indexI = 2; - } - else if (nu_fabs[1] < nu_fabs[2]) { - indexI = 2; - } - - /* Project origin onto the 1D simplex - line */ - pt = dotProduct(b, t) / (dotProduct(t, t)) * (a[indexI] - b[indexI]) + b[indexI]; - - /* Compute signed determinants */ - det_ap = a[indexI] - pt; - det_pb = pt - b[indexI]; - - /* Compare signs of AB and auxiliary simplices */ - FacetsTest[0] = SAMESIGN(t[indexI], -1 * det_ap); - FacetsTest[1] = SAMESIGN(t[indexI], -1 * det_pb); - - if (FacetsTest[0] + FacetsTest[1] == 2) { - /* The origin is between A and B */ - s->lambdas[0] = det_ap * -1.0 / t[indexI]; - s->lambdas[1] = 1 - s->lambdas[0]; - s->wids[0] = 0; - s->wids[1] = 1; - s->nvrtx = 2; - } - else if (FacetsTest[0] == 0) { - /* The origin is beyond A */ - s->lambdas[0] = 1; - s->wids[0] = 0; - s->nvrtx = 1; - for (i = 0; i < 3; ++i) { - s->vrtx[0][i] = s->vrtx[1][i]; - } - } - else { - /* The origin is behind B */ - s->lambdas[0] = 1; - s->wids[0] = 1; - s->nvrtx = 1; - } - - for (int j = 0; j < 3; ++j) { - vv[j] = 0; - for (i = 0; i < s->nvrtx; ++i) { - vv[j] += (s->lambdas[i] * s->vrtx[i][j]); - } - } -} - -/** - * @brief Finds point of minimum norm of 2-simplex. Robust, but slower, version of algorithm presented in paper. - */ -inline static void S2D(struct simplex * s, double *vv) { - int i; - int k; - int l; - int j; - int indexI = 1; - //int stemp[3]; - int FacetsTest[3]; - int indexJ[2] = { -1 }; - double nu_max = 0; - double inv_detM = 0; - double nnorm_sqrd = 0; - double nnnorm = 0; - double dotNA; - double a[3]; - double b[3]; - double c[3]; - double s21[3]; - double s31[3]; - double nu_test[3]; - double nu_fabs[3]; - double B[3]; - double n[3]; - double v[3]; - double vtmp[3]; - double pp[3 - 1]; - double sa[3 - 1]; - double sb[3 - 1]; - double sc[3 - 1]; - - - for (i = 0; i < 3; ++i) { - c[i] = s->vrtx[0][i]; - b[i] = s->vrtx[1][i]; - a[i] = s->vrtx[2][i]; - s21[i] = b[i] - a[i]; - s31[i] = c[i] - a[i]; - } - - /* Find best axis for projection */ - k = 1; l = 2; - for (i = 0; i < 3; ++i) { - nu_test[i] = pow(-1.0, i) * (b[k] * c[l] + a[k] * b[l] + c[k] * a[l] - b[k] * a[l] - c[k] * b[l] - a[k] * c[l]); - k = l; l = i; - } - - for (i = 0; i < 3; ++i) { - nu_fabs[i] = fabs(nu_test[i]); - } - - if (nu_fabs[0] > nu_fabs[1]) { - if (nu_fabs[0] > nu_fabs[2]) { - indexI = 0; - indexJ[0] = 1; - indexJ[1] = 2; - } - else { - indexJ[0] = 0; - indexJ[1] = 1; - indexI = 2; - } - } - else if (nu_fabs[0] < nu_fabs[1]) { - if (nu_fabs[1] > nu_fabs[2]) { - indexJ[0] = 0; - indexI = 1; - indexJ[1] = 2; - } - else { - indexJ[0] = 0; - indexJ[1] = 1; - indexI = 2; - } - } - else if (nu_fabs[0] < nu_fabs[2]) { - indexJ[0] = 0; - indexJ[1] = 1; - indexI = 2; - } - - nu_max = nu_test[indexI]; - - k = 1; l = 2; - for (i = 0; i < 3; ++i) { - n[i] = s21[k] * s31[l] - s21[l] * s31[k]; - nnorm_sqrd += n[i] * n[i]; - k = l; l = i; - } - nnnorm = 1 / sqrt(nnorm_sqrd); - for (i = 0; i < 3; ++i) { - n[i] = n[i] * nnnorm; - } - - dotNA = dotProduct(n, a); - - pp[0] = dotNA * n[indexJ[0]]; - pp[1] = dotNA * n[indexJ[1]]; - - /* Compute signed determinants */ -#ifndef ADAPTIVEFP - double ss[3][3 - 1]; - - ss[0][0] = sa[0] = a[indexJ[0]]; - ss[0][1] = sa[1] = a[indexJ[1]]; - ss[1][0] = sb[0] = b[indexJ[0]]; - ss[1][1] = sb[1] = b[indexJ[1]]; - ss[2][0] = sc[0] = c[indexJ[0]]; - ss[2][1] = sc[1] = c[indexJ[1]]; - - k = 1; l = 2; - for (i = 0; i < 3; ++i) { - B[i] = pp[0] * ss[k][1] + pp[1] * ss[l][0] + ss[k][0] * ss[l][1] - pp[0] * ss[l][1] - pp[1] * ss[k][0] - - ss[l][0] * ss[k][1]; - k = l; - l = i; - } -#else - - sa[0] = a[indexJ[0]]; - sa[1] = a[indexJ[1]]; - sb[0] = b[indexJ[0]]; - sb[1] = b[indexJ[1]]; - sc[0] = c[indexJ[0]]; - sc[1] = c[indexJ[1]]; - - B[0] = orient2d(sa, pp, sc); - B[1] = orient2d(sa, pp, sc); - B[2] = orient2d(sa, sb, pp); -#endif - - /* Test if sign of ABC is equal to the signes of the auxiliary simplices */ - for (i = 0; i < 3; ++i) { - FacetsTest[i] = SAMESIGN(nu_max, B[i]); - } - - // The nan check was not included originally and will be removed in v2.0 - if (FacetsTest[1] + FacetsTest[2] == 0 || isnan(n[0])) { - struct simplex sTmp; - - sTmp.nvrtx = 2; - s->nvrtx = 2; - for (i = 0; i < 3; ++i) { - - sTmp.vrtx[0][i] = s->vrtx[1][i]; - sTmp.vrtx[1][i] = s->vrtx[2][i]; - - s->vrtx[0][i] = s->vrtx[0][i]; - s->vrtx[1][i] = s->vrtx[2][i]; - } - - S1D(&sTmp, v); - S1D(s, v); - - for (j = 0; j < 3; ++j) { - vtmp[j] = 0; - v[j] = 0; - for (i = 0; i < sTmp.nvrtx; ++i) { - vtmp[j] += (sTmp.lambdas[i] * sTmp.vrtx[i][j]); - v[j] += (s->lambdas[i] * s->vrtx[i][j]); - } - } - - if (dotProduct(v, v) < dotProduct(vtmp, vtmp)) { - /* Keep simplex. Need to update sID only*/ - for (i = 1; i < s->nvrtx; ++i) { - s->wids[i] = s->wids[i] + 1; - } - } - else { - s->nvrtx = sTmp.nvrtx; - for (j = 0; j < 3; ++j) { - for (i = 0; i < s->nvrtx; ++i) { - s->vrtx[i][j] = s->vrtx[i][j]; - s->lambdas[i] = sTmp.lambdas[i]; - /* No need to convert sID here since sTmp deal with the vertices A and B. ;*/ - s->wids[i] = sTmp.wids[i]; - } - } - } - } - else if ((FacetsTest[0] + FacetsTest[1] + FacetsTest[2]) == 3) { - /* The origin projections lays onto the triangle */ - inv_detM = 1 / nu_max; - s->lambdas[0] = B[2] * inv_detM; - s->lambdas[1] = B[1] * inv_detM; - s->lambdas[2] = 1 - s->lambdas[0] - s->lambdas[1]; - s->wids[0] = 0; - s->wids[1] = 1; - s->wids[2] = 2; - s->nvrtx = 3; - } - else if (FacetsTest[2] == 0) { - /* The origin projection P faces the segment AB */ - s->nvrtx = 2; - for (i = 0; i < 3; ++i) { - s->vrtx[0][i] = s->vrtx[1][i]; - s->vrtx[1][i] = s->vrtx[2][i]; - } - S1D(s, v); - } - else if (FacetsTest[1] == 0) { - /* The origin projection P faces the segment AC */ - s->nvrtx = 2; - for (i = 0; i < 3; ++i) { - s->vrtx[0][i] = s->vrtx[0][i]; - s->vrtx[1][i] = s->vrtx[2][i]; - } - S1D(s, v); - for (i = 1; i < s->nvrtx; ++i) { - s->wids[i] = s->wids[i] + 1; - } - } - else { - /* The origin projection P faces the segment BC */ - s->nvrtx = 2; - S1D(s, v); - - } - - for ( j = 0; j < 3; ++j) { - vv[j] = 0; - for (i = 0; i < s->nvrtx; ++i) { - vv[j] += (s->lambdas[i] * s->vrtx[i][j]); - } - } -} - -/** - * @brief Finds point of minimum norm of 3-simplex. Robust, but slower, version of algorithm presented in paper. - */ -inline static void S3D(struct simplex * s, double *vv) { - int FacetsTest[4] = { 1,1,1,1 }; - int sID[4] = { 0, 0, 0, 0 }; - int TrianglesToTest[9] = { 3, 3, 3, 1, 2, 2, 0, 0, 1 }; - int i; - int j; - int k; - int l; - int vtxid; - int ndoubts = 0; - int nclosestS = 0; - int firstaux = 0; - int secondaux = 0; - int Flag_sAuxused = 0; - double a[3]; - double b[3]; - double c[3]; - double d[3]; - double vtmp[3]; - double v[3]; - double B[4]; - double tmplamda[4] = { 0, 0, 0, 0 }; - double tmpscoo1[4][3] = { 0 }; - double sqdist_tmp = 0; - double detM; - double inv_detM; -#ifdef ADAPTIVEFP - double o[3] = { 0 }; -#endif - for (i = 0; i < 3; ++i) { - d[i] = s->vrtx[0][i]; - c[i] = s->vrtx[1][i]; - b[i] = s->vrtx[2][i]; - a[i] = s->vrtx[3][i]; - } - -#ifndef ADAPTIVEFP - B[0] = -1 * (b[0] * c[1] * d[2] + b[1] * c[2] * d[0] + b[2] * c[0] * d[1] - b[2] * c[1] * d[0] - b[1] * c[0] * d[2] - b[0] * c[2] * d[1]); - B[1] = +1 * (a[0] * c[1] * d[2] + a[1] * c[2] * d[0] + a[2] * c[0] * d[1] - a[2] * c[1] * d[0] - a[1] * c[0] * d[2] - a[0] * c[2] * d[1]); - B[2] = -1 * (a[0] * b[1] * d[2] + a[1] * b[2] * d[0] + a[2] * b[0] * d[1] - a[2] * b[1] * d[0] - a[1] * b[0] * d[2] - a[0] * b[2] * d[1]); - B[3] = +1 * (a[0] * b[1] * c[2] + a[1] * b[2] * c[0] + a[2] * b[0] * c[1] - a[2] * b[1] * c[0] - a[1] * b[0] * c[2] - a[0] * b[2] * c[1]); - detM = B[0] + B[1] + B[2] + B[3]; -#else - B[0] = orient3d(o, b, c, d); - B[1] = orient3d(a, o, c, d); - B[2] = orient3d(a, b, o, d); - B[3] = orient3d(a, b, c, o); - detM = orient3d(a, b, c, d); -#endif - - /* Test if sign of ABCD is equal to the signes of the auxiliary simplices */ - double eps = 1e-13; - if (fabs(detM) < eps) - { - if (fabs(B[2]) < eps && fabs(B[3]) < eps) - FacetsTest[1] = 0; /* A = B. Test only ACD */ - else if (fabs(B[1]) < eps && fabs(B[3]) < eps) - FacetsTest[2] = 0; /* A = C. Test only ABD */ - else if (fabs(B[1]) < eps && fabs(B[2]) < eps) - FacetsTest[3] = 0; /* A = D. Test only ABC */ - else if (fabs(B[0]) < eps && fabs(B[3]) < eps) - FacetsTest[1] = 0; /* B = C. Test only ACD */ - else if (fabs(B[0]) < eps && fabs(B[2]) < eps) - FacetsTest[1] = 0; /* B = D. Test only ABD */ - else if (fabs(B[0]) < eps && fabs(B[1]) < eps) - FacetsTest[2] = 0; /* C = D. Test only ABC */ - else { - for (i = 0; i < 4; i++) - FacetsTest[i] = 0; /* Any other case. Test ABC, ABD, ACD */ - } - } - else - { - for (i = 0; i < 4; ++i) - FacetsTest[i] = SAMESIGN(detM, B[i]); - } - - /* Compare signed volumes and compute barycentric coordinates */ - if (FacetsTest[0] + FacetsTest[1] + FacetsTest[2] + FacetsTest[3] == 4) { - /* All signs are equal, therefore the origin is inside the simplex */ - inv_detM = 1 / detM; - s->lambdas[3] = B[0] * inv_detM; - s->lambdas[2] = B[1] * inv_detM; - s->lambdas[1] = B[2] * inv_detM; - s->lambdas[0] = 1 - s->lambdas[1] - s->lambdas[2] - s->lambdas[3]; - s->wids[0] = 0; - s->wids[1] = 1; - s->wids[2] = 2; - s->wids[3] = 3; - s->nvrtx = 4; - } - else if (FacetsTest[1] + FacetsTest[2] + FacetsTest[3] == 0) { - /* There are three facets facing the origin */ - ndoubts = 3; - - struct simplex sTmp; - - for (i = 0; i < ndoubts; ++i) { - sTmp.nvrtx = 3; - /* Assign coordinates to simplex */ - for (k = 0; k < sTmp.nvrtx; ++k) { - vtxid = TrianglesToTest[i + (k * 3)]; - for (j = 0; j < 3; ++j) { - sTmp.vrtx[2 - k][j] = s->vrtx[vtxid][j]; - } - } - /* ... and call S2D */ - S2D(&sTmp, v); - /* ... compute aux squared distance */ - for (j = 0; j < 3; ++j) { - vtmp[j] = 0; - for (l = 0; l < sTmp.nvrtx; ++l) { - vtmp[j] += sTmp.lambdas[l] * (sTmp.vrtx[l][j]); - } - } - - if (i == 0) { - sqdist_tmp = dotProduct(vtmp, vtmp); - nclosestS = sTmp.nvrtx; - for (l = 0; l < nclosestS; ++l) { - sID[l] = TrianglesToTest[i + (sTmp.wids[l] * 3)]; - tmplamda[l] = sTmp.lambdas[l]; - } - } - else if (dotProduct(vtmp, vtmp) < sqdist_tmp) { - sqdist_tmp = dotProduct(vtmp, vtmp); - nclosestS = sTmp.nvrtx; - for (l = 0; l < nclosestS; ++l) { - sID[l] = TrianglesToTest[i + (sTmp.wids[l] * 3)]; - tmplamda[l] = sTmp.lambdas[l]; - } - } - } - - for (i = 0; i < 4; ++i) { - for (j = 0; j < 3; ++j) { - tmpscoo1[i][j] = s->vrtx[i][j]; - } - } - - /* Store closest simplex */ - s->nvrtx = nclosestS; - for (i = 0; i < s->nvrtx; ++i) { - for (j = 0; j < 3; ++j) { - s->vrtx[nclosestS - 1 - i][j] = tmpscoo1[sID[i]][j]; - } - s->lambdas[i] = tmplamda[i]; - s->wids[nclosestS - 1 - i] = sID[i]; - } - } - else if (FacetsTest[1] + FacetsTest[2] + FacetsTest[3] == 1) { - /* There are two facets facing the origin, need to find the closest. */ - struct simplex sTmp; - sTmp.nvrtx = 3; - - if (FacetsTest[1] == 0) { - /* ... Test facet ACD */ - for (i = 0; i < 3; ++i) { - sTmp.vrtx[0][i] = s->vrtx[0][i]; - sTmp.vrtx[1][i] = s->vrtx[1][i]; - sTmp.vrtx[2][i] = s->vrtx[3][i]; - } - /* ... and call S2D */ - S2D(&sTmp, v); - /* ... compute aux squared distance */ - for (j = 0; j < 3; ++j) { - vtmp[j] = 0; - for (i = 0; i < sTmp.nvrtx; ++i) { - vtmp[j] += sTmp.lambdas[i] * (sTmp.vrtx[i][j]); - } - } - sqdist_tmp = dotProduct(vtmp, vtmp); - Flag_sAuxused = 1; - firstaux = 0; - } - if (FacetsTest[2] == 0) { - /* ... Test facet ABD */ - if (Flag_sAuxused == 0) { - - for (i = 0; i < 3; ++i) { - sTmp.vrtx[0][i] = s->vrtx[0][i]; - sTmp.vrtx[1][i] = s->vrtx[2][i]; - sTmp.vrtx[2][i] = s->vrtx[3][i]; - } - /* ... and call S2D */ - S2D(&sTmp, v); - /* ... compute aux squared distance */ - for (j = 0; j < 3; ++j) { - vtmp[j] = 0; - for (i = 0; i < sTmp.nvrtx; ++i) { - vtmp[j] += sTmp.lambdas[i] * (sTmp.vrtx[i][j]); - } - } - sqdist_tmp = dotProduct(vtmp, vtmp); - firstaux = 1; - } - else { - s->nvrtx = 3; - for (i = 0; i < 3; ++i) { - s->vrtx[0][i] = s->vrtx[0][i]; - s->vrtx[1][i] = s->vrtx[2][i]; - s->vrtx[2][i] = s->vrtx[3][i]; - } - /* ... and call S2D itself */ - S2D(s, v); - secondaux = 1; - } - } - - if (FacetsTest[3] == 0) { - /* ... Test facet ABC */ - s->nvrtx = 3; - for (i = 0; i < 3; ++i) { - s->vrtx[0][i] = s->vrtx[1][i]; - s->vrtx[1][i] = s->vrtx[2][i]; - s->vrtx[2][i] = s->vrtx[3][i]; - } - /* ... and call S2D */ - S2D(s, v); - secondaux = 2; - } - /* Compare outcomes */ - for (j = 0; j < 3; ++j) { - v[j] = 0; - for (i = 0; i < s->nvrtx; ++i) { - v[j] += s->lambdas[i] * (s->vrtx[i][j]); - } - } - if (dotProduct(v, v) < sqdist_tmp) { - /* Keep simplex. Need to update sID only*/ - for (i = 0; i < s->nvrtx; ++i) { - /* Assume that vertex a is always included in sID. */ - s->wids[s->nvrtx - 1 - i] = TrianglesToTest[secondaux + (s->wids[i] * 3)]; - } - } - else { - s->nvrtx = sTmp.nvrtx; - for (i = 0; i < s->nvrtx; ++i) { - for (j = 0; j < 3; ++j) { - s->vrtx[i][j] = sTmp.vrtx[i][j]; - } - s->lambdas[i] = sTmp.lambdas[i]; - s->wids[sTmp.nvrtx - 1 - i] = TrianglesToTest[firstaux + (sTmp.wids[i] * 3)]; - } - } - } - else if (FacetsTest[1] + FacetsTest[2] + FacetsTest[3] == 2) { - /* Only one facet is facing the origin */ - if (FacetsTest[1] == 0) { - /* The origin projection P faces the facet ACD */ - s->nvrtx = 3; - for (i = 0; i < 3; ++i) { - s->vrtx[0][i] = s->vrtx[0][i]; - s->vrtx[1][i] = s->vrtx[1][i]; - s->vrtx[2][i] = s->vrtx[3][i]; - } - S2D(s, v); - - /* Keep simplex. Need to update sID only*/ - for (i = 0; i < s->nvrtx; ++i) { - s->wids[i] = s->wids[i]; - } - } - else if (FacetsTest[2] == 0) { - /* The origin projection P faces the facet ABD */ - s->nvrtx = 3; - for (i = 0; i < 3; ++i) { - s->vrtx[0][i] = s->vrtx[0][i]; - s->vrtx[1][i] = s->vrtx[2][i]; - s->vrtx[2][i] = s->vrtx[3][i]; - } - S2D(s, v); - /* Keep simplex. Need to update sID only*/ - for (i = 2; i < s->nvrtx; ++i) { - /* Assume that vertex a is always included in sID. */ - s->wids[i] = s->wids[i] + 1; - } - } - else if (FacetsTest[3] == 0) { - /* The origin projection P faces the facet ABC */ - s->nvrtx = 3; - for (i = 0; i < 3; ++i) { - s->vrtx[0][i] = s->vrtx[1][i]; - s->vrtx[1][i] = s->vrtx[2][i]; - s->vrtx[2][i] = s->vrtx[3][i]; - } - S2D(s, v); - } - } - else { - /* The origin projection P faces the facet BCD */ - s->nvrtx = 3; - for (i = 0; i < 3; ++i) { - s->vrtx[0][i] = s->vrtx[0][i]; - s->vrtx[1][i] = s->vrtx[1][i]; - s->vrtx[2][i] = s->vrtx[2][i]; - } - /* ... and call S2D */ - S2D(s, v); - /* Keep simplex. Need to update sID only*/ - for (i = 0; i < s->nvrtx; ++i) { - /* Assume that vertex a is always included in sID. */ - s->wids[i] = s->wids[i] + 1; - } - } - - - for ( j = 0; j < 3; ++j) { - vv[j] = 0; - for (i = 0; i < s->nvrtx; ++i) { - vv[j] += (s->lambdas[i] * s->vrtx[i][j]); - } - } -} - - -inline static void support( struct bd *body, double *v ) { - int better = -1; - int i; - double s; - double maxs; - double *vrt; - - maxs = dotProduct(body->s, v); - - for (i = 0; i < body->numpoints; ++i) { - vrt = body->coord[i]; - s = dotProduct (vrt, v); - if ( s > maxs ){ - maxs = s; - better = i; - } - } - - if (better != -1 ){ - body->s[0] = body->coord[better][0]; - body->s[1] = body->coord[better][1]; - body->s[2] = body->coord[better][2]; - } -} - -inline static void subalgorithm( struct simplex *s, double *v ) { - - switch ( s->nvrtx ){ - case 4: - S3D( s, v ); - break; - case 3: - S2D( s, v ); - break; - case 2: - S1D( s, v ); - break; - } -} - -double gjk( struct bd bd1, struct bd bd2, struct simplex *s) { - - int i; - int k = 0; /**< Iteration counter */ - int mk = 50; /**< Maximum number of iterations of the GJK algorithm */ - int exeedtol_rel = 0; /**< Flag for 1st exit condition */ - double v[3]; /**< Search direction */ - double vminus[3]; /**< Search direction * -1 */ - double w[3]; /**< Vertex on CSO boundary given by the difference of support functions on both bodies */ - double eps_rel = 1e-5; /**< Tolerance on relative distance */ - double eps_tot = 1e-15; /**< Tolerance on absolute distance */ - double norm2Wmax = 0; - double tesnorm = 0; - -#ifdef ADAPTIVEFP - exactinit(); -#endif - - double eps_rel2 = eps_rel * eps_rel ; - - /* Initialise */ - s->nvrtx = 1; - for ( i = 0; i < 3; i++) - { - v[i] = bd1.coord[0][i] - bd2.coord[0][i]; - bd1.s[i] = bd1.coord[0][i]; - bd2.s[i] = bd2.coord[0][i]; - s->vrtx[0][i] = v[i]; - s->p[0][i] = bd1.s[i]; - s->q[0][i] = bd2.s[i]; - } - - /* Begin GJK iteration */ - do { - - k++; - - /* Update negative search direction */ - vminus[0] = -v[0]; - vminus[1] = -v[1]; - vminus[2] = -v[2]; - - /* Support function */ - support( &bd1 , vminus ); - support( &bd2 , v ); - w[0] = bd1.s[0] - bd2.s[0]; - w[1] = bd1.s[1] - bd2.s[1]; - w[2] = bd1.s[2] - bd2.s[2]; - - /* 1st exit condition */ - exeedtol_rel = (norm2(v) - dotProduct (v,w) ) <= eps_rel2 * norm2(v); - if ( exeedtol_rel ){ - break; - } - - /* 2nd exit condition */ - if (norm2(v) < eps_rel2) - break; - - /* Add new vertex to simplex */ - i = s->nvrtx; - s->vrtx[i][0] = w[0]; - s->vrtx[i][1] = w[1]; - s->vrtx[i][2] = w[2]; - s->nvrtx++; - - /* Invoke distance sub-algorithm */ - subalgorithm ( s, v ); - - for (i = 0; i < 3; i++) - { - s->p[s->nvrtx - 1][i] = bd1.s[i]; - s->q[s->nvrtx - 1][i] = bd2.s[i]; - } - - /* 3rd exit condition */ - for (i = 0; i < s->nvrtx; i++) - { - tesnorm = norm2(s->vrtx[i]); - if (tesnorm > norm2Wmax) { - norm2Wmax = tesnorm; - } - } - if (norm2(v) <= (eps_tot * eps_tot * norm2Wmax)) - break; - - /* 4th and 5th exit conditions */ - } while((s->nvrtx != 4) && (k != mk)); - - /* Compute and return distance */ - return sqrt(norm2(v)); -} - -#ifdef MATLABDOESMEXSTUFF -/** - * @brief Mex function for Matlab. - */ -void mexFunction( int nlhs, mxArray *plhs[], - int nrhs, const mxArray *prhs[]) -{ - - double *inCoordsA; - double *inCoordsB; - size_t nCoordsA; - size_t nCoordsB; - int i; - double *distance; - int c = 3; - int count = 0; - double**arr1; - double**arr2; - - /**************** PARSE INPUTS AND OUTPUTS **********************/ - /*----------------------------------------------------------------*/ - /* Examine input (right-hand-side) arguments. */ - if(nrhs!=2) { - mexErrMsgIdAndTxt("MyToolbox:gjk:nrhs","Two inputs required."); - } - /* Examine output (left-hand-side) arguments. */ - if(nlhs!=1) { - mexErrMsgIdAndTxt("MyToolbox:gjk:nlhs","One output required."); - } - - /* make sure the two input arguments are any numerical type */ - /* .. first input */ - if( !mxIsNumeric(prhs[0])) { - mexErrMsgIdAndTxt("MyToolbox:gjk:notNumeric","Input matrix must be type numeric."); - } - /* .. second input */ - if( !mxIsNumeric(prhs[1])) { - mexErrMsgIdAndTxt("MyToolbox:gjk:notNumeric","Input matrix must be type numeric."); - } - - /* make sure the two input arguments have 3 columns */ - /* .. first input */ - if(mxGetM(prhs[0])!=3) { - mexErrMsgIdAndTxt("MyToolbox:gjk:notColumnVector","First input must have 3 columns."); - } - /* .. second input */ - if(mxGetM(prhs[1])!=3) { - mexErrMsgIdAndTxt("MyToolbox:gjk:notColumnVector","Second input must have 3 columns."); - } - - /*----------------------------------------------------------------*/ - /* CREATE DATA COMPATIBLE WITH MATALB */ - - /* create a pointer to the real data in the input matrix */ - inCoordsA = mxGetPr(prhs[0]); - inCoordsB = mxGetPr(prhs[1]); - - /* get the length of each input vector */ - nCoordsA = mxGetN(prhs[0]); - nCoordsB = mxGetN(prhs[1]); - - /* Create output */ - plhs[0]=mxCreateDoubleMatrix(1,1,mxREAL); - - /* get a pointer to the real data in the output matrix */ - distance = mxGetPr(plhs[0]); - - /* Copy data from Matlab's vectors into two new arrays */ - arr1 = (double **)mxMalloc( sizeof(double *) * (int)nCoordsA ); - arr2 = (double **)mxMalloc( sizeof(double *) * (int)nCoordsB ); - - for (i = 0; i < nCoordsA; i++) - arr1[i] = &inCoordsA[i * 3]; - - for (i = 0; i < nCoordsB; i++) - arr2[i] = &inCoordsB[i * 3]; - - /*----------------------------------------------------------------*/ - /* POPULATE BODIES' STRUCTURES */ - - struct bd bd1; /* Structure of body A */ - struct bd bd2; /* Structure of body B */ - - /* Assign number of vertices to each body */ - bd1.numpoints = (int) nCoordsA; - bd2.numpoints = (int) nCoordsB; - - bd1.coord = arr1; - bd2.coord = arr2; - - /*----------------------------------------------------------------*/ - /*CALL COMPUTATIONAL ROUTINE */ - - struct simplex s; - s.nvrtx = 0; - - /* Compute squared distance using GJK algorithm */ - distance[0] = gjk (bd1, bd2, &s); - - mxFree(arr1); - mxFree(arr2); - -} -#endif - -/** - * @brief Invoke this function from C# applications - */ -double csFunction( int nCoordsA, double *inCoordsA, int nCoordsB, double *inCoordsB ) -{ - double distance = 0; - int i, j; - - /*----------------------------------------------------------------*/ - /* POPULATE BODIES' STRUCTURES */ - - struct bd bd1; /* Structure of body A */ - struct bd bd2; /* Structure of body B */ - - /* Assign number of vertices to each body */ - bd1.numpoints = (int) nCoordsA; - bd2.numpoints = (int) nCoordsB; - - double **pinCoordsA = (double **)malloc(bd1.numpoints * sizeof(double *)); - for (i=0; i< bd1.numpoints ; i++) - pinCoordsA[i] = (double *)malloc(3 * sizeof(double)); - - for (i = 0; i < 3; i++) - for (j = 0; j < bd1.numpoints; j++) - pinCoordsA[j][i] = inCoordsA[ i*bd1.numpoints + j] ; - - double **pinCoordsB = (double **)malloc(bd2.numpoints * sizeof(double *)); - for (i=0; i< bd2.numpoints ; i++) - pinCoordsB[i] = (double *)malloc(3 * sizeof(double)); - - for (i = 0; i < 3; i++) - for (j = 0; j < bd2.numpoints; j++) - pinCoordsB[j][i] = inCoordsB[ i*bd2.numpoints + j] ; - - bd1.coord = pinCoordsA; - bd2.coord = pinCoordsB; - - - /*----------------------------------------------------------------*/ - /*CALL COMPUTATIONAL ROUTINE */ - struct simplex s; - - /* Initialise simplex as empty */ - s.nvrtx = 0; - - /* Compute squared distance using GJK algorithm */ - distance = gjk (bd1, bd2, &s); - - for (i=0; i< bd1.numpoints ; i++) - free(pinCoordsA[i]); - free( pinCoordsA ); - - for (i=0; i< bd2.numpoints ; i++) - free(pinCoordsB[i]); - free( pinCoordsB ); - - return distance; -} diff --git a/src/openGJK.c b/src/openGJK.c new file mode 100644 index 0000000..7066525 --- /dev/null +++ b/src/openGJK.c @@ -0,0 +1,946 @@ +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * + * ##### # # # * + * #### ##### ###### # # # # # # # * + * # # # # # ## # # # # # * + * # # # # ##### # # # # #### # ### * + * # # ##### # # # # # # # # # # * + * # # # # # ## # # # # # # * + * #### # ###### # # ##### ##### # # * + * * + * This file is part of openGJK. * + * * + * openGJK is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * any later version. * + * * + * openGJK is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See The * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with Foobar. If not, see . * + * * + * openGJK: open-source Gilbert-Johnson-Keerthi algorithm * + * Copyright (C) Mattia Montanari 2018 - 2019 * + * http://iel.eng.ox.ac.uk/?page_id=504 * + * * + * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +#include "openGJK/openGJK.h" + +/* If instricuted, compile a mex function for Matlab. */ +#ifdef MATLABDOESMEXSTUFF +#include "mex.h" +#else +#define mexPrintf printf +#endif + +#define eps_rel22 1e-10 +#define eps_tot22 1e-12 + +/* Select distance sub-algorithm */ + +#define norm2(a) (a[0]*a[0]+a[1]*a[1]+a[2]*a[2]) + +#define dotProduct(a, b) (a[0]*b[0]+a[1]*b[1]+a[2]*b[2]) + +#define S3Dregion1234() v[0] = 0;\ + v[1] = 0;\ + v[2] = 0;\ + s->nvrtx = 4; + +#define select_1ik() s->nvrtx = 3;\ + for (t = 0; t < 3; t++)\ + s->vrtx[2][t] = s->vrtx[3][t];\ + for (t = 0; t < 3; t++)\ + s->vrtx[1][t] = si[t];\ + for (t = 0; t < 3; t++)\ + s->vrtx[0][t] = sk[t]; + +#define select_1ij() s->nvrtx = 3;\ + for (t = 0; t < 3; t++)\ + s->vrtx[2][t] = s->vrtx[3][t];\ + for (t = 0; t < 3; t++)\ + s->vrtx[1][t] = si[t];\ + for (t = 0; t < 3; t++)\ + s->vrtx[0][t] = sj[t]; + +#define select_1jk() s->nvrtx = 3;\ + for (t = 0; t < 3; t++)\ + s->vrtx[2][t] = s->vrtx[3][t];\ + for (t = 0; t < 3; t++)\ + s->vrtx[1][t] = sj[t];\ + for (t = 0; t < 3; t++)\ + s->vrtx[0][t] = sk[t]; + +#define select_1i() s->nvrtx = 2;\ + for (t = 0; t < 3; t++)\ + s->vrtx[1][t] = s->vrtx[3][t];\ + for (t = 0; t < 3; t++)\ + s->vrtx[0][t] = si[t]; + +#define select_1j() s->nvrtx = 2;\ + for (t = 0; t < 3; t++)\ + s->vrtx[1][t] = s->vrtx[3][t];\ + for (t = 0; t < 3; t++)\ + s->vrtx[0][t] = sj[t]; + +#define select_1k() s->nvrtx = 2;\ + for (t = 0; t < 3; t++)\ + s->vrtx[1][t] = s->vrtx[3][t];\ + for (t = 0; t < 3; t++)\ + s->vrtx[0][t] = sk[t]; + +#define getvrtx(point, location) point[0] = s->vrtx[location][0];\ + point[1] = s->vrtx[location][1];\ + point[2] = s->vrtx[location][2]; + +#define calculateEdgeVector(p1p2, p2) p1p2[0] = p2[0] - s->vrtx[3][0];\ + p1p2[1] = p2[1] - s->vrtx[3][1];\ + p1p2[2] = p2[2] - s->vrtx[3][2]; + +#define S1Dregion1() v[0] = s->vrtx[1][0];\ + v[1] = s->vrtx[1][1];\ + v[2] = s->vrtx[1][2];\ + s->nvrtx = 1;\ + s->vrtx[0][0] = s->vrtx[1][0];\ + s->vrtx[0][1] = s->vrtx[1][1];\ + s->vrtx[0][2] = s->vrtx[1][2]; + +#define S2Dregion1() v[0] = s->vrtx[2][0];\ + v[1] = s->vrtx[2][1];\ + v[2] = s->vrtx[2][2];\ + s->nvrtx = 1;\ + s->vrtx[0][0] = s->vrtx[2][0];\ + s->vrtx[0][1] = s->vrtx[2][1];\ + s->vrtx[0][2] = s->vrtx[2][2]; + +#define S2Dregion12() s->nvrtx = 2;\ + s->vrtx[0][0] = s->vrtx[2][0];\ + s->vrtx[0][1] = s->vrtx[2][1];\ + s->vrtx[0][2] = s->vrtx[2][2]; + +#define S2Dregion13() s->nvrtx = 2;\ + s->vrtx[1][0] = s->vrtx[2][0];\ + s->vrtx[1][1] = s->vrtx[2][1];\ + s->vrtx[1][2] = s->vrtx[2][2]; + +#define S3Dregion1() v[0] = s1[0];\ + v[1] = s1[1];\ + v[2] = s1[2];\ + s->nvrtx = 1;\ + s->vrtx[0][0] = s1[0];\ + s->vrtx[0][1] = s1[1];\ + s->vrtx[0][2] = s1[2]; + +inline static double determinant(const double *p, const double *q, const double *r) { + return p[0] * ((q[1] * r[2]) - (r[1] * q[2])) - p[1] * (q[0] * r[2] - r[0] * q[2]) + p[2] * (q[0] * r[1] - r[0] * q[1]); +} + +inline static void crossProduct(const double *a, const double *b, double *c) +{ + c[0] = a[1] * b[2] - a[2] * b[1]; + c[1] = a[2] * b[0] - a[0] * b[2]; + c[2] = a[0] * b[1] - a[1] * b[0]; +} + +inline static void projectOnLine(const double *p, const double *q, double *v) +{ + double pq[3]; + double tmp; + pq[0] = p[0] - q[0]; + pq[1] = p[1] - q[1]; + pq[2] = p[2] - q[2]; + + tmp = dotProduct(p, pq) / dotProduct(pq, pq); + + for (int i = 0; i < 3; i++) + v[i] = p[i] - pq[i] * tmp; +} + +inline static void projectOnPlane(const double *p, const double *q, const double *r, double *v) +{ + double n[3], pq[3], pr[3]; + double tmp; + + for (int i = 0; i < 3; i++) + pq[i] = p[i] - q[i]; + + for (int i = 0; i < 3; i++) + pr[i] = p[i] - r[i]; + + crossProduct(pq, pr, n); + tmp = dotProduct(n, p) / dotProduct(n, n); + + for (int i = 0; i < 3; i++) + v[i] = n[i] * tmp; +} + +inline static int hff1(const double *p, const double *q) +{ + double tmp = 0; + +#pragma omp simd reduction(+:tmp) + for (int i = 0; i < 3; i++) + tmp += (p[i] * p[i] - p[i] * q[i]); + + if (tmp > 0) + return 1; // keep q + + return 0; +} + +inline static int hff2(const double *p, const double *q, const double *r) +{ + double ntmp[3]; + double n[3], pq[3], pr[3]; + double tmp = 0; + + for (int i = 0; i < 3; i++) + pq[i] = q[i] - p[i]; + + for (int i = 0; i < 3; i++) + pr[i] = r[i] - p[i]; + + crossProduct(pq, pr, ntmp); + crossProduct(pq, ntmp, n); + +#pragma omp simd reduction(+:tmp) + for (int i = 0; i < 3; i++) + tmp = tmp + (p[i] * n[i]); + + if (tmp < 0) + return 1; // Discard r + + return 0; +} + +inline static int hff3(const double *p, const double *q, const double *r) +{ + double n[3], pq[3], pr[3]; + double tmp = 0; + + for (int i = 0; i < 3; i++) + pq[i] = q[i] - p[i]; + + for (int i = 0; i < 3; i++) + pr[i] = r[i] - p[i]; + + crossProduct(pq, pr, n); + +#pragma omp simd reduction(+:tmp) + for (int i = 0; i < 3; i++) + tmp = tmp + (p[i] * n[i]); + + if (tmp > 0) + return 0; // discard s + + return 1; +} + +inline static void S1D(struct simplex * s, double *v) +{ + double *s1p = s->vrtx[1]; + double *s2p = s->vrtx[0]; + + if (hff1(s1p, s2p)) { + projectOnLine(s1p, s2p, v); // Update v, no need to update s + return; // Return V{1,2} + } + else { + S1Dregion1(); // Update v and s + return; // Return V{1} + } +} + + +inline static void S2D(struct simplex * s, double *v) +{ + double *s1p = s->vrtx[2]; + double *s2p = s->vrtx[1]; + double *s3p = s->vrtx[0]; + int hff1f_s12 = hff1(s1p, s2p); + int hff1f_s13 = hff1(s1p, s3p); + int hff2f_23 = !hff2(s1p, s2p, s3p); + int hff2f_32 = !hff2(s1p, s3p, s2p); + + if (hff1f_s12) { + if (hff2f_23) { + if (hff1f_s13) { + if (hff2f_32) { + projectOnPlane(s1p, s2p, s3p, v); // Update s, no need to update c + return; // Return V{1,2,3} + } + else + { + projectOnLine(s1p, s3p, v); // Update v + S2Dregion13(); // Update s + return; // Return V{1,3} + } + } + else + { + projectOnPlane(s1p, s2p, s3p, v); // Update s, no need to update c + return; // Return V{1,2,3} + } + } + else + { + projectOnLine(s1p, s2p, v); // Update v + S2Dregion12(); // Update s + return; // Return V{1,2} + } + } + else if (hff1f_s13) { + if (hff2f_32) { + projectOnPlane(s1p, s2p, s3p, v); // Update s, no need to update v + return; // Return V{1,2,3} + } + else + { + projectOnLine(s1p, s3p, v); // Update v + S2Dregion13(); // Update s + return; // Return V{1,3} + } + } + else { + S2Dregion1(); // Update s and v + return; // Return V{1} + } + +} + +inline static void S3D(struct simplex * s, double *v) { + + double s1[3], s2[3], s3[3], s4[3], s1s2[3], s1s3[3], s1s4[3]; + double si[3], sj[3], sk[3]; + int testLineThree, testLineFour, testPlaneTwo, testPlaneThree, testPlaneFour, dotTotal; + int i, j, k, t; + + getvrtx(s1, 3); + getvrtx(s2, 2); + getvrtx(s3, 1); + getvrtx(s4, 0); + calculateEdgeVector(s1s2, s2); + calculateEdgeVector(s1s3, s3); + calculateEdgeVector(s1s4, s4); + + int hff1_tests[3]; + hff1_tests[2] = hff1(s1, s2); + hff1_tests[1] = hff1(s1, s3); + hff1_tests[0] = hff1(s1, s4); + testLineThree = hff1(s1, s3); + testLineFour = hff1(s1, s4); + + dotTotal = hff1(s1, s2) + testLineThree + testLineFour; + if (dotTotal == 0) { /* case 0.0 -------------------------------------- */ + S3Dregion1(); + return; + } + + double det134 = determinant(s1s3, s1s4, s1s2); + int sss; + if (det134 > 0) { + sss = 0; + } + else { + sss = 1; + } + + testPlaneTwo = hff3(s1, s3, s4) - sss; + testPlaneTwo = testPlaneTwo * testPlaneTwo; + testPlaneThree = hff3(s1, s4, s2) - sss; + testPlaneThree = testPlaneThree * testPlaneThree; + testPlaneFour = hff3(s1, s2, s3) - sss; + testPlaneFour = testPlaneFour * testPlaneFour; + + switch (testPlaneTwo + testPlaneThree + testPlaneFour) { + case 3: + S3Dregion1234(); + break; + + case 2: + // Only one facing the oring + // 1,i,j, are the indices of the points on the triangle and remove k from simplex + s->nvrtx = 3; + if (!testPlaneTwo) { // k = 2; removes s2 + for (i = 0; i < 3; i++) + s->vrtx[2][i] = s->vrtx[3][i]; + } + else if (!testPlaneThree) {// k = 1; // removes s3 + for (i = 0; i < 3; i++) + s->vrtx[1][i] = s2[i]; + for (i = 0; i < 3; i++) + s->vrtx[2][i] = s->vrtx[3][i]; + } + else if (!testPlaneFour) { // k = 0; // removes s4 and no need to reorder + for (i = 0; i < 3; i++) + s->vrtx[0][i] = s3[i]; + for (i = 0; i < 3; i++) + s->vrtx[1][i] = s2[i]; + for (i = 0; i < 3; i++) + s->vrtx[2][i] = s->vrtx[3][i]; + } + // Call S2D + S2D(s, v); + break; + case 1: + // Two triangles face the origins: + // The only positive hff3 is for triangle 1,i,j, therefore k must be in the solution as it supports the the point of minimum norm. + + // 1,i,j, are the indices of the points on the triangle and remove k from simplex + s->nvrtx = 3; + if (testPlaneTwo) { + k = 2; // s2 + i = 1; + j = 0; + } + else if (testPlaneThree) { + k = 1; // s3 + i = 0; + j = 2; + } + else { + k = 0; // s4 + i = 2; + j = 1; + } + + getvrtx(si, i); + getvrtx(sj, j); + getvrtx(sk, k); + + if (dotTotal == 1) { + if (hff1_tests[k]) { + if (!hff2(s1, sk, si)) { + select_1ik(); + projectOnPlane(s1, si, sk, v); + } + else if (!hff2(s1, sk, sj)) { + select_1jk(); + projectOnPlane(s1, sj, sk, v); + } + else { + select_1k(); // select region 1i + projectOnLine(s1, sk, v); + } + } + else if (hff1_tests[i]) { + if (!hff2(s1, si, sk)) { + select_1ik(); + projectOnPlane(s1, si, sk, v); + } + else { + select_1i(); // select region 1i + projectOnLine(s1, si, v); + } + } + else { + if (!hff2(s1, sj, sk)) { + select_1jk(); + projectOnPlane(s1, sj, sk, v); + } + else { + select_1j(); // select region 1i + projectOnLine(s1, sj, v); + } + } + } + else if (dotTotal == 2) { + // Two edges have positive hff1, meaning that for two edges the origin's project fall on the segement. + // Certainly the edge 1,k supports the the point of minimum norm, and so hff1_1k is positive + + if (hff1_tests[i]) { + if (!hff2(s1, sk, si)) + if (!hff2(s1, si, sk)) { + select_1ik(); // select region 1ik + projectOnPlane(s1, si, sk, v); + } + else { + select_1k(); // select region 1k + projectOnLine(s1, sk, v); + } + else { + if (!hff2(s1, sk, sj)) { + select_1jk(); // select region 1jk + projectOnPlane(s1, sj, sk, v); + } + else { + select_1k(); // select region 1k + projectOnLine(s1, sk, v); + } + } + } + else if (hff1_tests[j]) {// there is no other choice + if (!hff2(s1, sk, sj)) + if (!hff2(s1, sj, sk)) { + select_1jk(); // select region 1jk + projectOnPlane(s1, sj, sk, v); + } + else { + select_1j(); // select region 1j + projectOnLine(s1, sj, v); + } + else { + if (!hff2(s1, sk, si)) { + select_1ik(); // select region 1ik + projectOnPlane(s1, si, sk, v); + } + else { + select_1k(); // select region 1k + projectOnLine(s1, sk, v); + } + } + } + else { + // ERROR; + } + + } + else if (dotTotal == 3) { + // MM : ALL THIS HYPHOTESIS IS FALSE + // sk is s.t. hff3 for sk < 0. So, sk must support the origin because there are 2 triangles facing the origin. + + int hff2_ik = hff2(s1,si,sk); + int hff2_jk = hff2(s1,sj,sk); + int hff2_ki = hff2(s1,sk,si); + int hff2_kj = hff2(s1,sk,sj); + + if (hff2_ki == 0 && hff2_kj == 0){ + mexPrintf("\n\n UNEXPECTED VALUES!!! \n\n"); + } + if (hff2_ki == 1 && hff2_kj == 1){ + select_1k(); + projectOnLine(s1, sk, v); + } + else if (hff2_ki) { + // discard i + if (hff2_jk){ + // discard k + select_1j(); + projectOnLine(s1, sj, v); + } + else{ + select_1jk(); + projectOnPlane(s1, sk, sj, v); + } + } + else { + // discard j + if (hff2_ik){ + // discard k + select_1i(); + projectOnLine(s1, si, v); + } + else{ + select_1ik(); + projectOnPlane(s1, sk, si, v); + } + } + } + break; + + case 0: + // The origin is outside all 3 triangles + if (dotTotal == 1) { + // Here si is set such that hff(s1,si) > 0 + if (testLineThree) { + k = 2; + i = 1; // s3 + j = 0; + } + else if (testLineFour) { + k = 1; // s3 + i = 0; + j = 2; + } + else { + k = 0; + i = 2; // s2 + j = 1; + } + getvrtx(si, i); + getvrtx(sj, j); + getvrtx(sk, k); + + if (!hff2(s1, si, sj)) { + select_1ij(); + projectOnPlane(s1, si, sj, v); + } + else if (!hff2(s1, si, sk)) { + select_1ik(); + projectOnPlane(s1, si, sk, v); + } + else { + select_1i(); + projectOnLine(s1, si, v); + } + } + else if (dotTotal == 2) { + // Here si is set such that hff(s1,si) < 0 + s->nvrtx = 3; + if (!testLineThree) { + k = 2; + i = 1; // s3 + j = 0; + } + else if (!testLineFour) { + k = 1; + i = 0; // s4 + j = 2; + } + else { + k = 0; + i = 2; // s2 + j = 1; + } + getvrtx(si, i); + getvrtx(sj, j); + getvrtx(sk, k); + + if (!hff2(s1, sj, sk)) { + if (!hff2(s1, sk, sj)) { + select_1jk(); // select region 1jk + projectOnPlane(s1, sj, sk, v); + } + else if (!hff2(s1, sk, si)) { + select_1ik(); + projectOnPlane(s1, sk, si, v); + } + else { + select_1k(); + projectOnLine(s1, sk, v); + } + } + else if (!hff2(s1, sj, si)) { + select_1ij(); + projectOnPlane(s1, si, sj, v); + } + else { + select_1j(); + projectOnLine(s1, sj, v); + } + } + break; + default: + mexPrintf("\nERROR:\tunhandled"); + } + +} + +inline static void support(struct bd *body, const double *v) { + + double s, maxs; + double *vrt; + int better = -1; + + maxs = dotProduct(body->s, v); + + for (int i = 0; i < body->numpoints; ++i) { + vrt = body->coord[i]; + s = dotProduct(vrt, v); + if (s > maxs) { + maxs = s; + better = i; + } + } + + if (better != -1) { + body->s[0] = body->coord[better][0]; + body->s[1] = body->coord[better][1]; + body->s[2] = body->coord[better][2]; + } +} + +inline static void subalgorithm(struct simplex *s, double *v) { + + switch (s->nvrtx) { + case 4: + S3D(s, v); + break; + case 3: + S2D(s, v); + break; + case 2: + S1D(s, v); + break; + default: + mexPrintf("\nERROR:\t invalid simplex\n"); + } +} + +double gjk(struct bd bd1, struct bd bd2, struct simplex *s) { + + int k = 0; /**< Iteration counter */ + int i; /**< General purpose counter */ + int mk = 25; /**< Maximum number of iterations of the GJK algorithm */ + int absTestin; + double norm2Wmax = 0; + double tesnorm; + double v[3]; /**< Search direction */ + double vminus[3]; /**< Search direction * -1 */ + double w[3]; /**< Vertex on CSO boundary given by the difference of support functions on both bodies */ + double eps_rel = eps_rel22; /**< Tolerance on relative */ + double eps_rel2 = eps_rel * eps_rel; + double eps_tot = eps_tot22; + double exeedtol_rel; /**< Test for 1st exit condition */ + int nullV = 0; + +#ifdef DEBUG + mexPrintf("Num points A = %i \n", bd1.numpoints); + mexPrintf("Num points B = %i \n", bd2.numpoints); + for (i = 0; i < bd1.numpoints; ++i) { + for (int j = 0; j < 3; j++) { + mexPrintf("%.4f ", bd1.coord[i][j]); + } + mexPrintf("\n"); + } + + for (i = 0; i < bd2.numpoints; ++i) { + for (int j = 0; j < 3; j++) { + mexPrintf("%.4f ", bd2.coord[i][j]); + } + mexPrintf("\n"); + } +#endif + + /* Initialise search direction */ + v[0] = bd1.coord[0][0] - bd2.coord[0][0]; + v[1] = bd1.coord[0][1] - bd2.coord[0][1]; + v[2] = bd1.coord[0][2] - bd2.coord[0][2]; + + /* Inialise simplex */ + s->nvrtx = 1; + for (int t = 0; t < 3; ++t) + s->vrtx[0][t] = v[t]; + + for (int t = 0; t < 3; ++t) + bd1.s[t] = bd1.coord[0][t]; + + for (int t = 0; t < 3; ++t) + bd2.s[t] = bd2.coord[0][t]; + + /* Begin GJK iteration */ + do { + + k++; + + /* Update negative search direction */ + for (int t = 0; t < 3; ++t) + vminus[t] = -v[t]; + + /* Support function */ + support(&bd1, vminus); + support(&bd2, v); + for (int t = 0; t < 3; ++t) + w[t] = bd1.s[t] - bd2.s[t]; + + /* Test first exit condition (new point already in simplex/can't move further) */ + exeedtol_rel = (norm2(v) - dotProduct(v, w)); + if ( exeedtol_rel <= (eps_rel * norm2(v)) || exeedtol_rel < eps_tot22) { + break; + } + + nullV = norm2(v) < eps_rel2; + if (nullV) { + break; + } + + /* Add new vertex to simplex */ + i = s->nvrtx; + for (int t = 0; t < 3; ++t) + s->vrtx[i][t] = w[t]; + s->nvrtx++; + + /* Invoke distance sub-algorithm */ + subalgorithm(s, v); + + /* Test */ + for (int jj = 0; jj < s->nvrtx; jj++) { + tesnorm = norm2(s->vrtx[jj]); + if (tesnorm > norm2Wmax) { + norm2Wmax = tesnorm; + } + } + + absTestin = (norm2(v) <= (eps_tot * eps_tot * norm2Wmax)); + if (absTestin) { + break; + } + + } while ((s->nvrtx != 4) && (k != mk)); + + if (k == mk) { + mexPrintf("\n * * * * * * * * * * * * MAXIMUM ITERATION NUMBER REACHED!!! * * * * * * * * * * * * * * \n"); + } + + return sqrt(norm2(v)); +} + + + +#ifdef MATLABDOESMEXSTUFF +/** + * @brief Mex function for Matlab. + */ +void mexFunction(int nlhs, mxArray *plhs[], + int nrhs, const mxArray *prhs[]) +{ + + double *inCoordsA; + double *inCoordsB; + size_t nCoordsA; + size_t nCoordsB; + int i; + double *distance; + int c = 3; + int count = 0; + double**arr1; + double**arr2; + + /**************** PARSE INPUTS AND OUTPUTS **********************/ + /*----------------------------------------------------------------*/ + /* Examine input (right-hand-side) arguments. */ + if (nrhs != 2) { + mexErrMsgIdAndTxt("MyToolbox:gjk:nrhs", "Two inputs required."); + } + /* Examine output (left-hand-side) arguments. */ + if (nlhs != 1) { + mexErrMsgIdAndTxt("MyToolbox:gjk:nlhs", "One output required."); + } + + /* make sure the two input arguments are any numerical type */ + /* .. first input */ + if (!mxIsNumeric(prhs[0])) { + mexErrMsgIdAndTxt("MyToolbox:gjk:notNumeric", "Input matrix must be type numeric."); + } + /* .. second input */ + if (!mxIsNumeric(prhs[1])) { + mexErrMsgIdAndTxt("MyToolbox:gjk:notNumeric", "Input matrix must be type numeric."); + } + + /* make sure the two input arguments have 3 columns */ + /* .. first input */ + if (mxGetM(prhs[0]) != 3) { + mexErrMsgIdAndTxt("MyToolbox:gjk:notColumnVector", "First input must have 3 columns."); + } + /* .. second input */ + if (mxGetM(prhs[1]) != 3) { + mexErrMsgIdAndTxt("MyToolbox:gjk:notColumnVector", "Second input must have 3 columns."); + } + + /*----------------------------------------------------------------*/ + /* CREATE DATA COMPATIBLE WITH MATALB */ + + /* create a pointer to the real data in the input matrix */ + inCoordsA = mxGetPr(prhs[0]); + inCoordsB = mxGetPr(prhs[1]); + + /* get the length of each input vector */ + nCoordsA = mxGetN(prhs[0]); + nCoordsB = mxGetN(prhs[1]); + + /* Create output */ + plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); + + /* get a pointer to the real data in the output matrix */ + distance = mxGetPr(plhs[0]); + + /* Copy data from Matlab's vectors into two new arrays */ + arr1 = (double **)mxMalloc(sizeof(double *) * (int)nCoordsA); + arr2 = (double **)mxMalloc(sizeof(double *) * (int)nCoordsB); + + for (i = 0; i < nCoordsA; i++) + arr1[i] = &inCoordsA[i * 3]; + + for (i = 0; i < nCoordsB; i++) + arr2[i] = &inCoordsB[i * 3]; + + /*----------------------------------------------------------------*/ + /* POPULATE BODIES' STRUCTURES */ + + struct bd bd1; /* Structure of body A */ + struct bd bd2; /* Structure of body B */ + + /* Assign number of vertices to each body */ + bd1.numpoints = (int)nCoordsA; + bd2.numpoints = (int)nCoordsB; + + bd1.coord = arr1; + bd2.coord = arr2; + + /*----------------------------------------------------------------*/ + /*CALL COMPUTATIONAL ROUTINE */ + + struct simplex s; + s.nvrtx = 0; + + /* Compute squared distance using GJK algorithm */ + distance[0] = gjk(bd1, bd2, &s); + + mxFree(arr1); + mxFree(arr2); + +} +#endif + +/** + * @brief Invoke this function from C# applications + */ +double csFunction(int nCoordsA, double *inCoordsA, int nCoordsB, double *inCoordsB) +{ + double distance = 0; + int i, j; + + /*----------------------------------------------------------------*/ + /* POPULATE BODIES' STRUCTURES */ + + struct bd bd1; /* Structure of body A */ + struct bd bd2; /* Structure of body B */ + + /* Assign number of vertices to each body */ + bd1.numpoints = (int)nCoordsA; + bd2.numpoints = (int)nCoordsB; + + double **pinCoordsA = (double **)malloc(bd1.numpoints * sizeof(double *)); + for (i = 0; i < bd1.numpoints; i++) + pinCoordsA[i] = (double *)malloc(3 * sizeof(double)); + + for (i = 0; i < 3; i++) + for (j = 0; j < bd1.numpoints; j++) + pinCoordsA[j][i] = inCoordsA[i*bd1.numpoints + j]; + + double **pinCoordsB = (double **)malloc(bd2.numpoints * sizeof(double *)); + for (i = 0; i < bd2.numpoints; i++) + pinCoordsB[i] = (double *)malloc(3 * sizeof(double)); + + for (i = 0; i < 3; i++) + for (j = 0; j < bd2.numpoints; j++) + pinCoordsB[j][i] = inCoordsB[i*bd2.numpoints + j]; + + bd1.coord = pinCoordsA; + bd2.coord = pinCoordsB; + + + /*----------------------------------------------------------------*/ + /*CALL COMPUTATIONAL ROUTINE */ + struct simplex s; + + /* Initialise simplex as empty */ + s.nvrtx = 0; + + /* Compute squared distance using GJK algorithm */ + distance = gjk(bd1, bd2, &s); + + for (i = 0; i < bd1.numpoints; i++) + free(pinCoordsA[i]); + free(pinCoordsA); + + for (i = 0; i < bd2.numpoints; i++) + free(pinCoordsB[i]); + free(pinCoordsB); + + return distance; +}