diff --git a/.gitignore b/.gitignore index d7767ebfd..09fee2574 100644 --- a/.gitignore +++ b/.gitignore @@ -49,3 +49,4 @@ IfcPlusPlus/src/ifcpp- IfcPlusPlus/src/ifcpp-- IfcPlusPlus/src/ifcpp---/ IfcPlusPlus/src/ifcpp----/ +examples/LoadFileExample/dump_mesh_debug.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 94c276f97..b59cddc4b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,7 +65,6 @@ INSTALL( IF(BUILD_CONSOLE_APPLICATION) ADD_SUBDIRECTORY (examples/CreateIfcWallAndWriteFile) ADD_SUBDIRECTORY (examples/LoadFileExample) - ADD_SUBDIRECTORY (examples/LoadFileWithGeometryExample) ENDIF() IF(BUILD_VIEWER_APPLICATION) ADD_SUBDIRECTORY (examples/SimpleViewerExampleQt) diff --git a/IfcPlusPlus/CMakeLists.txt b/IfcPlusPlus/CMakeLists.txt index 286ffdc3c..1f08df0ab 100644 --- a/IfcPlusPlus/CMakeLists.txt +++ b/IfcPlusPlus/CMakeLists.txt @@ -40,21 +40,6 @@ set(IFCPP_SOURCE_FILES src/ifcpp/writer/WriterUtil.cpp src/ifcpp/geometry/MeshOps.cpp src/ifcpp/geometry/GeometryInputData.cpp - src/external/manifold/src/boolean3.cpp - src/external/manifold/src/boolean_result.cpp - src/external/manifold/src/collider/src/collider.cpp - src/external/manifold/src/constructors.cpp - src/external/manifold/src/csg_tree.cpp - src/external/manifold/src/edge_op.cpp - src/external/manifold/src/face_op.cpp - src/external/manifold/src/impl.cpp - src/external/manifold/src/manifold.cpp - src/external/manifold/src/polygon/src/polygon.cpp - src/external/manifold/src/properties.cpp - src/external/manifold/src/smoothing.cpp - src/external/manifold/src/sort.cpp - src/external/manifold/src/third_party/graphlite/src/connected_components.cpp - src/external/manifold/src/utilities/src/detect_cuda.cpp src/external/Carve/src/lib/aabb.cpp src/external/Carve/src/lib/carve.cpp src/external/Carve/src/lib/convex_hull.cpp @@ -116,15 +101,6 @@ TARGET_INCLUDE_DIRECTORIES(IfcPlusPlus ${IFCPP_SOURCE_DIR}/IfcPlusPlus/src/external/Carve/src/common ${IFCPP_SOURCE_DIR}/IfcPlusPlus/src/external/Carve/build/src ${IFCPP_SOURCE_DIR}/IfcPlusPlus/src/external/glm - ${IFCPP_SOURCE_DIR}/IfcPlusPlus/src/external/manifold/src/utilities/include - ${IFCPP_SOURCE_DIR}/IfcPlusPlus/src/external/manifold/src/utilities - ${IFCPP_SOURCE_DIR}/IfcPlusPlus/src/external/manifold/src/polygon/include - ${IFCPP_SOURCE_DIR}/IfcPlusPlus/src/external/manifold/src/manifold/include - ${IFCPP_SOURCE_DIR}/IfcPlusPlus/src/external/manifold/src - ${IFCPP_SOURCE_DIR}/IfcPlusPlus/src/external/manifold/src/collider/include - ${IFCPP_SOURCE_DIR}/IfcPlusPlus/src/external/manifold/src/third_party - ${IFCPP_SOURCE_DIR}/IfcPlusPlus/src/external/manifold/src/third_party/thrust - ${IFCPP_SOURCE_DIR}/IfcPlusPlus/src/external/manifold/src/third_party/graphlite/include ) diff --git a/IfcPlusPlus/IfcPlusPlus.vcxproj b/IfcPlusPlus/IfcPlusPlus.vcxproj index 81ab7d38a..321c99d0e 100644 --- a/IfcPlusPlus/IfcPlusPlus.vcxproj +++ b/IfcPlusPlus/IfcPlusPlus.vcxproj @@ -158,7 +158,7 @@ Level3 Disabled - src;../Carve/src/;../Carve/src/include;../Carve/src/common;src/external/manifold/src/utilities/include;src/external/manifold/src/utilities;src/external/manifold/src/polygon/include;src/external/manifold/src/manifold/include;src/external/manifold/src;src\external\manifold\src\collider\include;src/external/manifold/src/third_party;src/external/manifold/src/third_party/thrust;src/external/manifold/src/third_party/graphlite/include;%(AdditionalIncludeDirectories) + src;../Carve/src/;../Carve/src/include;../Carve/src/common;%(AdditionalIncludeDirectories) _WINDOWS;WINDOWS;UNICODE;WIN32;_DEBUG;_CRT_SECURE_NO_WARNINGS;_MBCS;IFCPP_AS_DYNAMIC_LIBRARY;IFCPP_LIB;GLM_FORCE_CTOR_INIT;GLM_FORCE_XYZW_ONLY;THRUST_DEVICE_SYSTEM=THRUST_DEVICE_SYSTEM_CPP;%(PreprocessorDefinitions) true ProgramDatabase @@ -173,7 +173,7 @@ Level3 Disabled - .;.\src;src\ifcpp;src\ifcpp\IFC4X3\include;.\src\external\;.\src\external\RapidJSON;.\src\external\glm;src/external/Carve;src/external/Carve/src;src/external/Carve/src/common;src/external/Carve/src/lib;src/external/Carve/src/include;src/external/Carve/src/include/carve;src/external/manifold/src/utilities/include;src/external/manifold/src/utilities;src/external/manifold/src/polygon/include;src/external/manifold/src/manifold/include;src/external/manifold/src;src\external\manifold\src\collider\include;src/external/manifold/src/third_party;src/external/manifold/src/third_party/thrust;src/external/manifold/src/third_party/graphlite/include;%(AdditionalIncludeDirectories) + .;.\src;src\ifcpp;src\ifcpp\IFC4X3\include;.\src\external\;.\src\external\RapidJSON;.\src\external\glm;src/external/Carve;src/external/Carve/src;src/external/Carve/src/common;src/external/Carve/src/lib;src/external/Carve/src/include;src/external/Carve/src/include/carve;%(AdditionalIncludeDirectories) _WINDOWS;WINDOWS;UNICODE;WIN32;WIN64;_DEBUG;_CRT_SECURE_NO_WARNINGS;_MBCS;GLM_FORCE_CTOR_INIT;GLM_FORCE_XYZW_ONLY;THRUST_DEVICE_SYSTEM=THRUST_DEVICE_SYSTEM_CPP;IFCQUERY_STATIC_LIB;%(PreprocessorDefinitions) true false @@ -206,7 +206,7 @@ MaxSpeed true true - src;../Carve/src/;../Carve/src/include;../Carve/src/common;src/external/manifold/src/utilities/include;src/external/manifold/src/utilities;src/external/manifold/src/polygon/include;src/external/manifold/src/manifold/include;src/external/manifold/src;src\external\manifold\src\collider\include;src/external/manifold/src/third_party;src/external/manifold/src/third_party/thrust;src/external/manifold/src/third_party/graphlite/include;%(AdditionalIncludeDirectories) + src;../Carve/src/;../Carve/src/include;../Carve/src/common;%(AdditionalIncludeDirectories) true Speed UNICODE;WIN32;_WINDOWS;NDEBUG;_MBCS;IFCQUERY_AS_DYNAMIC_LIBRARY;IFCQUERY_LIB;GLM_FORCE_CTOR_INIT;GLM_FORCE_XYZW_ONLY;THRUST_DEVICE_SYSTEM=THRUST_DEVICE_SYSTEM_CPP;%(PreprocessorDefinitions) @@ -252,7 +252,7 @@ MaxSpeed true false - .;.\src;src\ifcpp;src\ifcpp\IFC4X3\include;.\src\external\;.\src\external\RapidJSON;.\src\external\glm;src/external/Carve;src/external/Carve/src;src/external/Carve/src/common;src/external/Carve/src/lib;src/external/Carve/src/include;src/external/Carve/src/include/carve;src/external/manifold/src/utilities/include;src/external/manifold/src/utilities;src/external/manifold/src/polygon/include;src/external/manifold/src/manifold/include;src/external/manifold/src;src\external\manifold\src\collider\include;src/external/manifold/src/third_party;src/external/manifold/src/third_party/thrust;src/external/manifold/src/third_party/graphlite/include;%(AdditionalIncludeDirectories) + .;.\src;src\ifcpp;src\ifcpp\IFC4X3\include;.\src\external\;.\src\external\RapidJSON;.\src\external\glm;src/external/Carve;src/external/Carve/src;src/external/Carve/src/common;src/external/Carve/src/lib;src/external/Carve/src/include;src/external/Carve/src/include/carve;%(AdditionalIncludeDirectories) true UNICODE;WIN32;_WINDOWS;NDEBUG;_MBCS;IFCQUERY_LIB;GLM_FORCE_CTOR_INIT;GLM_FORCE_XYZW_ONLY;THRUST_DEVICE_SYSTEM=THRUST_DEVICE_SYSTEM_CPP;IFCQUERY_STATIC_LIB;%(PreprocessorDefinitions) true @@ -300,7 +300,7 @@ MaxSpeed true true - src;../Carve/src/;../Carve/src/include;../Carve/src/common;src/external/manifold/src/utilities/include;src/external/manifold/src/utilities;src/external/manifold/src/polygon/include;src/external/manifold/src/manifold/include;src/external/manifold/src;src\external\manifold\src\collider\include;src/external/manifold/src/third_party;src/external/manifold/src/third_party/thrust;src/external/manifold/src/third_party/graphlite/include;%(AdditionalIncludeDirectories) + src;../Carve/src/;../Carve/src/include;../Carve/src/common;%(AdditionalIncludeDirectories) true UNICODE;WIN32;_WINDOWS;NDEBUG;_MBCS;GLM_FORCE_CTOR_INIT;GLM_FORCE_XYZW_ONLY;THRUST_DEVICE_SYSTEM=THRUST_DEVICE_SYSTEM_CPP;%(PreprocessorDefinitions) true @@ -323,7 +323,7 @@ MaxSpeed true true - src;../Carve/src/;../Carve/src/include;../Carve/src/common;src/external/manifold/src/utilities/include;src/external/manifold/src/utilities;src/external/manifold/src/polygon/include;src/external/manifold/src/manifold/include;src/external/manifold/src;src\external\manifold\src\collider\include;src/external/manifold/src/third_party;src/external/manifold/src/third_party/thrust;src/external/manifold/src/third_party/graphlite/include;%(AdditionalIncludeDirectories) + src;../Carve/src/;../Carve/src/include;../Carve/src/common;%(AdditionalIncludeDirectories) true UNICODE;WIN32;_WINDOWS;NDEBUG;_MBCS;GLM_FORCE_CTOR_INIT;GLM_FORCE_XYZW_ONLY;THRUST_DEVICE_SYSTEM=THRUST_DEVICE_SYSTEM_CPP;%(PreprocessorDefinitions) true @@ -341,7 +341,6 @@ - @@ -358,21 +357,6 @@ - - - - - - - - - - - - - - - diff --git a/IfcPlusPlus/IfcPlusPlus.vcxproj.filters b/IfcPlusPlus/IfcPlusPlus.vcxproj.filters index a6a555a47..bc5229413 100644 --- a/IfcPlusPlus/IfcPlusPlus.vcxproj.filters +++ b/IfcPlusPlus/IfcPlusPlus.vcxproj.filters @@ -185,51 +185,7 @@ Quelldateien - - Quelldateien - - - Quelldateien - - - Quelldateien - - - Quelldateien - - - Quelldateien - - - Quelldateien - - - Quelldateien - - - Quelldateien - - - Quelldateien - - - Quelldateien - - - Quelldateien - - - Quelldateien - - - Quelldateien - - - Quelldateien - - - Quelldateien - + Quelldateien @@ -317,9 +273,6 @@ Quelldateien - - Quelldateien - Quelldateien diff --git a/IfcPlusPlus/src/external/manifold/AUTHORS b/IfcPlusPlus/src/external/manifold/AUTHORS deleted file mode 100644 index 9a20a3e9e..000000000 --- a/IfcPlusPlus/src/external/manifold/AUTHORS +++ /dev/null @@ -1,9 +0,0 @@ -# This is the list of Manifold's significant contributors. -# -# This does not necessarily list everyone who has contributed code, -# especially since many employees of one corporation may be contributing. -# To see the full list of contributors, see the revision history in -# source control. -Emmett Lalish -Chun Kit LAM -Google LLC \ No newline at end of file diff --git a/IfcPlusPlus/src/external/manifold/CMakeLists.txt b/IfcPlusPlus/src/external/manifold/CMakeLists.txt deleted file mode 100644 index 4625f0e58..000000000 --- a/IfcPlusPlus/src/external/manifold/CMakeLists.txt +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 The Manifold Authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -project (manifold) - -file(GLOB_RECURSE SOURCE_FILES CONFIGURE_DEPENDS *.cpp) -add_library(${PROJECT_NAME} ${SOURCE_FILES}) - -if(MANIFOLD_USE_CUDA) - set_source_files_properties( ${SOURCE_FILES} PROPERTIES LANGUAGE CUDA) - set_property(TARGET ${PROJECT_NAME} PROPERTY CUDA_ARCHITECTURES 61) -endif() - -target_include_directories(${PROJECT_NAME} PUBLIC ${PROJECT_SOURCE_DIR}/include ) -target_link_libraries(${PROJECT_NAME} - PUBLIC utilities - PRIVATE collider polygon ${MANIFOLD_INCLUDE} graphlite -) - -target_compile_features(${PROJECT_NAME} - PUBLIC cxx_std_14 - PRIVATE cxx_std_17 -) - diff --git a/IfcPlusPlus/src/external/manifold/CONTRIBUTING.md b/IfcPlusPlus/src/external/manifold/CONTRIBUTING.md deleted file mode 100644 index 9d7656bec..000000000 --- a/IfcPlusPlus/src/external/manifold/CONTRIBUTING.md +++ /dev/null @@ -1,29 +0,0 @@ -# How to Contribute - -We'd love to accept your patches and contributions to this project. There are -just a few small guidelines you need to follow. - -## Contributor License Agreement - -Contributions to this project must be accompanied by a Contributor License -Agreement (CLA). You (or your employer) retain the copyright to your -contribution; this simply gives us permission to use and redistribute your -contributions as part of the project. Head over to - to see your current agreements on file or -to sign a new one. - -You generally only need to submit a CLA once, so if you've already submitted one -(even if it was for a different project), you probably don't need to do it -again. - -## Code Reviews - -All submissions, including submissions by project members, require review. We -use GitHub pull requests for this purpose. Consult -[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more -information on using pull requests. - -## Community Guidelines - -This project follows -[Google's Open Source Community Guidelines](https://opensource.google/conduct/). \ No newline at end of file diff --git a/IfcPlusPlus/src/external/manifold/LICENSE b/IfcPlusPlus/src/external/manifold/LICENSE deleted file mode 100644 index 261eeb9e9..000000000 --- a/IfcPlusPlus/src/external/manifold/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/IfcPlusPlus/src/external/manifold/README.md b/IfcPlusPlus/src/external/manifold/README.md deleted file mode 100644 index 252429387..000000000 --- a/IfcPlusPlus/src/external/manifold/README.md +++ /dev/null @@ -1,106 +0,0 @@ -[![codecov](https://codecov.io/github/elalish/manifold/branch/master/graph/badge.svg?token=IIA8G5HVS7)](https://codecov.io/github/elalish/manifold) -[![twitter](https://img.shields.io/twitter/follow/manifoldcad?style=social&logo=twitter)](https://twitter.com/intent/follow?screen_name=manifoldcad) - -## [ManifoldCAD.org](https://manifoldcad.org) - -If you like OpenSCAD / OpenJSCAD, you might also like ManifoldCAD - our own solid modelling web app. The operations are not GPU-accelerated, but it's still pretty fast and a good way to test out our Manifold library. - -![A metallic Menger sponge](https://elalish.github.io/manifold/samples/models/mengerSponge3.webp "A metallic Menger sponge") - -# Manifold - -[**High-level Documentation**](https://elalish.blogspot.com/search/label/Manifold) | [**API Documentation**](https://elalish.github.io/manifold/docs/html/modules.html) | [**Algorithm Documentation**](https://github.com/elalish/manifold/wiki/Manifold-Library) | [**Web Examples**](https://elalish.github.io/manifold/model-viewer.html) - -[Manifold](https://github.com/elalish/manifold) is a geometry library dedicated to creating and operating on manifold triangle meshes. A [manifold mesh](https://github.com/elalish/manifold/wiki/Manifold-Library#manifoldness) is a mesh that represents a solid object, and so is very important in manufacturing, CAD, structural analysis, etc. Further information can be found on the [wiki](https://github.com/elalish/manifold/wiki/Manifold-Library). - -This is a modern C++ library that Github's CI verifies builds and runs on a variety of platforms. Additionally, we build bindings for JavaScript ([manifold-3d](https://www.npmjs.com/package/manifold-3d) on npm) and Python to make this library more portable and easy to use. We have only three dependencies (all built-in header-only libraries): graphlite provides a connected components algorithm, GLM is a compact vector library, and Thrust is Nvidia's parallel algorithms library (basically a superset of C++17 std::parallel_algorithms). We make use of submodules to ensure compatibility. - -## What's here - -This library is fast with guaranteed manifold output. As such you need manifold meshes as input, which this library can create using constructors inspired by the OpenSCAD API, as well as more advanced features like smoothing and signed-distance function (SDF) level sets. You can also pass in your own mesh data, but you'll get an error status if the imported mesh isn't manifold. Various automated repair tools exist online for fixing non manifold models, usually for 3D printing. - -The most significant contribution here is a guaranteed-manifold [mesh Boolean](https://github.com/elalish/manifold/wiki/Manifold-Library#mesh-boolean) algorithm, which I believe is the first of its kind. If you know of another, please open a discussion - a mesh Boolean algorithm robust to edge cases has been an open problem for many years. Likewise, if the Boolean here ever fails you, please submit an issue! This Boolean forms the basis of a CAD kernel, as it allows simple shapes to be combined into more complex ones. - -To aid in speed, this library makes extensive use of parallelization, generally through Nvidia's Thrust library. You can switch between the CUDA, OMP and serial C++ backends by setting a CMake flag. Not everything is so parallelizable, for instance a [polygon triangulation](https://github.com/elalish/manifold/wiki/Manifold-Library#polygon-triangulation) algorithm is included which is serial. Even if compiled for CUDA, the code will still run without a GPU, falling back to the serial version of the algorithms. The WASM build is serial-only for now, but still fast. - -Look in the [samples](https://github.com/elalish/manifold/tree/master/samples) directory for examples of how to use this library to make interesting 3D models. You may notice that some of these examples bare a certain resemblance to my OpenSCAD designs on [Thingiverse](https://www.thingiverse.com/emmett), which is no accident. Much as I love OpenSCAD, my library is dramatically faster and the code is more flexible. - -## Building - -Only CMake, a C++ compiler, and Python are required to be installed and set up to build this library (it has been tested with GCC, LLVM, MSVC). However, a variety of optional dependencies can bring in more functionality, see below. - -Build and test (Ubuntu or similar): -``` -git clone --recurse-submodules https://github.com/elalish/manifold.git -cd manifold -git apply thrust.diff -mkdir build -cd build -cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=ON .. && make -test/manifold_test -``` - -CMake flags (usage e.g. `-DMANIFOLD_USE_CUDA=ON`): -- `MANIFOLD_USE_CUDA=[, ON]`: Provides Nvidia GPU parallelization, requires CUDA Toolkit and its nvcc compiler. -- `MANIFOLD_PAR=[, OMP, TBB]`: Provides multi-thread parallelization, requires `libomp-dev` or `libtbb-dev`. -- `MANIFOLD_EXPORT=[, ON]`: Enables GLB export of 3D models from the tests, requires `libassimp-dev`. -- `MANIFOLD_DEBUG=[, ON]`: Enables internal assertions and exceptions. -- `BUILD_TEST_CGAL=[, ON]`: Builds a CGAL-based performance [comparison](https://github.com/elalish/manifold/tree/master/extras), requires `libcgal-dev`. - -The build instructions used by our CI are in [manifold.yml](https://github.com/elalish/manifold/blob/master/.github/workflows/manifold.yml), which is a good source to check if something goes wrong and for instructions specific to other platforms, like Windows. - -### WASM -To build the JS WASM library, first install NodeJS and set up emscripten: - -(on Mac): -``` -brew install nodejs -brew install emscripten -``` -(on Linux): -``` -sudo apt install nodejs -git clone https://github.com/emscripten-core/emsdk.git -cd emsdk -./emsdk install latest -./emsdk activate latest -source ./emsdk/emsdk_env.sh -``` -Then build: -``` -cd manifold -mkdir buildWASM -cd buildWASM -emcmake cmake -DCMAKE_BUILD_TYPE=Release .. && emmake make -node test/manifold_test.js -``` - -### Python - -The CMake script will build the python binding `pymanifold` automatically. To -use the extension, please add `$BUILD_DIR/tools` to your `PYTHONPATH`, where -`$BUILD_DIR` is the build directory for CMake. Examples using the python binding -can be found in `bindings/python/examples`. To see exported samples, run: -``` -sudo apt install pkg-config libpython3-dev python3 python3-distutils python3-pip -pip install trimesh -python3 run_all.py -e -``` - -Run the following code in the interpreter for -python binding documentation: - -``` ->>> import pymanifold ->>> help(pymanifold) -``` - -For more detailed documentation, please refer to the C++ API. - -## Contributing - -Contributions are welcome! A lower barrier contribution is to simply make a PR that adds a test, especially if it repros an issue you've found. Simply name it prepended with DISABLED_, so that it passes the CI. That will be a very strong signal to me to fix your issue. However, if you know how to fix it yourself, then including the fix in your PR would be much appreciated! - -## About the author - -This library was started by [Emmett Lalish](https://elalish.blogspot.com/). I am currently a Google employee and this is my 20% project, not an official Google project. At my day job I'm the maintainer of [\](https://modelviewer.dev/). I was the first employee at a 3D video startup, [Omnivor](https://www.omnivor.io/), and before that I worked on 3D printing at Microsoft, including [3D Builder](https://www.microsoft.com/en-us/p/3d-builder/9wzdncrfj3t6?activetab=pivot%3Aoverviewtab). Originally an aerospace engineer, I started at a small DARPA contractor doing seedling projects, one of which became [Sea Hunter](https://en.wikipedia.org/wiki/Sea_Hunter). I earned my doctorate from the University of Washington in control theory and published some [papers](https://www.researchgate.net/scientific-contributions/75011026_Emmett_Lalish). diff --git a/IfcPlusPlus/src/external/manifold/src/CMakeLists.txt b/IfcPlusPlus/src/external/manifold/src/CMakeLists.txt deleted file mode 100644 index 989db9710..000000000 --- a/IfcPlusPlus/src/external/manifold/src/CMakeLists.txt +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright 2022 The Manifold Authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -add_subdirectory(third_party) -add_subdirectory(utilities) -add_subdirectory(collider) -add_subdirectory(polygon) -add_subdirectory(manifold) -add_subdirectory(sdf) diff --git a/IfcPlusPlus/src/external/manifold/src/boolean3.cpp b/IfcPlusPlus/src/external/manifold/src/boolean3.cpp deleted file mode 100644 index a60a495ae..000000000 --- a/IfcPlusPlus/src/external/manifold/src/boolean3.cpp +++ /dev/null @@ -1,617 +0,0 @@ -// Copyright 2021 The Manifold Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "boolean3.h" - -#include - -#include "par.h" - -using namespace manifold; - -namespace { - -// These two functions (Interpolate and Intersect) are the only places where -// floating-point operations take place in the whole Boolean function. These are -// carefully designed to minimize rounding error and to eliminate it at edge -// cases to ensure consistency. - -__host__ __device__ glm::vec2 Interpolate(glm::vec3 pL, glm::vec3 pR, float x) { - float dxL = x - pL.x; - float dxR = x - pR.x; -#ifdef MANIFOLD_DEBUG - if (dxL * dxR > 0) printf("Not in domain!\n"); -#endif - bool useL = fabs(dxL) < fabs(dxR); - float lambda = (useL ? dxL : dxR) / (pR.x - pL.x); - if (!isfinite(lambda)) return glm::vec2(pL.y, pL.z); - glm::vec2 yz; - yz[0] = (useL ? pL.y : pR.y) + lambda * (pR.y - pL.y); - yz[1] = (useL ? pL.z : pR.z) + lambda * (pR.z - pL.z); - return yz; -} - -__host__ __device__ glm::vec4 Intersect(const glm::vec3 &pL, - const glm::vec3 &pR, - const glm::vec3 &qL, - const glm::vec3 &qR) { - float dyL = qL.y - pL.y; - float dyR = qR.y - pR.y; -#ifdef MANIFOLD_DEBUG - if (dyL * dyR > 0) printf("No intersection!\n"); -#endif - bool useL = fabs(dyL) < fabs(dyR); - float dx = pR.x - pL.x; - float lambda = (useL ? dyL : dyR) / (dyL - dyR); - if (!isfinite(lambda)) lambda = 0.0f; - glm::vec4 xyzz; - xyzz.x = (useL ? pL.x : pR.x) + lambda * dx; - float pDy = pR.y - pL.y; - float qDy = qR.y - qL.y; - bool useP = fabs(pDy) < fabs(qDy); - xyzz.y = (useL ? (useP ? pL.y : qL.y) : (useP ? pR.y : qR.y)) + - lambda * (useP ? pDy : qDy); - xyzz.z = (useL ? pL.z : pR.z) + lambda * (pR.z - pL.z); - xyzz.w = (useL ? qL.z : qR.z) + lambda * (qR.z - qL.z); - return xyzz; -} - -struct CopyFaceEdges { - // x can be either vert or edge (0 or 1). - thrust::pair pXq1; - const Halfedge *halfedgesQ; - - __host__ __device__ void operator()(thrust::tuple in) { - int idx = 3 * thrust::get<0>(in); - const int pX = thrust::get<1>(in); - const int q2 = thrust::get<2>(in); - - for (const int i : {0, 1, 2}) { - pXq1.first[idx + i] = pX; - const int q1 = 3 * q2 + i; - const Halfedge edge = halfedgesQ[q1]; - pXq1.second[idx + i] = edge.IsForward() ? q1 : edge.pairedHalfedge; - } - } -}; - -SparseIndices Filter11(const Manifold::Impl &inP, const Manifold::Impl &inQ, - const SparseIndices &p1q2, const SparseIndices &p2q1, - ExecutionPolicy policy) { - SparseIndices p1q1(3 * p1q2.size() + 3 * p2q1.size()); - for_each_n(policy, zip(countAt(0), p1q2.begin(0), p1q2.begin(1)), p1q2.size(), - CopyFaceEdges({p1q1.ptrDpq(), inQ.halfedge_.cptrD()})); - - p1q1.SwapPQ(); - for_each_n(policy, zip(countAt(p1q2.size()), p2q1.begin(1), p2q1.begin(0)), - p2q1.size(), - CopyFaceEdges({p1q1.ptrDpq(), inP.halfedge_.cptrD()})); - p1q1.SwapPQ(); - p1q1.Unique(policy); - return p1q1; -} - -__host__ __device__ bool Shadows(float p, float q, float dir) { - return p == q ? dir < 0 : p < q; -} - -/** - * Since this function is called from two different places, it is necessary that - * it returns identical results for identical input to keep consistency. - * Normally this is trivial as computers make floating-point errors, but are - * at least deterministic. However, in the case of CUDA, these functions can be - * compiled by two different compilers (for the CPU and GPU). We have found that - * the different compilers can cause slightly different rounding errors, so it - * is critical that the two places this function is called both use the same - * compiled function (they must agree on CPU or GPU). This is now taken care of - * by the shared policy_ member. - */ -__host__ __device__ thrust::pair Shadow01( - const int p0, const int q1, const glm::vec3 *vertPosP, - const glm::vec3 *vertPosQ, const Halfedge *halfedgeQ, const float expandP, - const glm::vec3 *normalP, const bool reverse) { - const int q1s = halfedgeQ[q1].startVert; - const int q1e = halfedgeQ[q1].endVert; - const float p0x = vertPosP[p0].x; - const float q1sx = vertPosQ[q1s].x; - const float q1ex = vertPosQ[q1e].x; - int s01 = reverse ? Shadows(q1sx, p0x, expandP * normalP[q1s].x) - - Shadows(q1ex, p0x, expandP * normalP[q1e].x) - : Shadows(p0x, q1ex, expandP * normalP[p0].x) - - Shadows(p0x, q1sx, expandP * normalP[p0].x); - glm::vec2 yz01(NAN); - - if (s01 != 0) { - yz01 = Interpolate(vertPosQ[q1s], vertPosQ[q1e], vertPosP[p0].x); - if (reverse) { - glm::vec3 diff = vertPosQ[q1s] - vertPosP[p0]; - const float start2 = glm::dot(diff, diff); - diff = vertPosQ[q1e] - vertPosP[p0]; - const float end2 = glm::dot(diff, diff); - const float dir = start2 < end2 ? normalP[q1s].y : normalP[q1e].y; - if (!Shadows(yz01[0], vertPosP[p0].y, expandP * dir)) s01 = 0; - } else { - if (!Shadows(vertPosP[p0].y, yz01[0], expandP * normalP[p0].y)) s01 = 0; - } - } - return thrust::make_pair(s01, yz01); -} - -__host__ __device__ int BinarySearch( - const thrust::pair keys, const int size, - const thrust::pair key) { - if (size <= 0) return -1; - int left = 0; - int right = size - 1; - int m; - thrust::pair keyM; - while (1) { - m = right - (right - left) / 2; - keyM = thrust::make_pair(keys.first[m], keys.second[m]); - if (left == right) break; - if (keyM > key) - right = m - 1; - else - left = m; - } - if (keyM == key) - return m; - else - return -1; -} - -struct Kernel11 { - const glm::vec3 *vertPosP; - const glm::vec3 *vertPosQ; - const Halfedge *halfedgeP; - const Halfedge *halfedgeQ; - float expandP; - const glm::vec3 *normalP; - - __host__ __device__ void operator()( - thrust::tuple inout) { - glm::vec4 &xyzz11 = thrust::get<0>(inout); - int &s11 = thrust::get<1>(inout); - const int p1 = thrust::get<2>(inout); - const int q1 = thrust::get<3>(inout); - - // For pRL[k], qRL[k], k==0 is the left and k==1 is the right. - int k = 0; - glm::vec3 pRL[2], qRL[2]; - // Either the left or right must shadow, but not both. This ensures the - // intersection is between the left and right. - bool shadows = false; - s11 = 0; - - const int p0[2] = {halfedgeP[p1].startVert, halfedgeP[p1].endVert}; - for (int i : {0, 1}) { - const auto syz01 = Shadow01(p0[i], q1, vertPosP, vertPosQ, halfedgeQ, - expandP, normalP, false); - const int s01 = syz01.first; - const glm::vec2 yz01 = syz01.second; - // If the value is NaN, then these do not overlap. - if (isfinite(yz01[0])) { - s11 += s01 * (i == 0 ? -1 : 1); - if (k < 2 && (k == 0 || (s01 != 0) != shadows)) { - shadows = s01 != 0; - pRL[k] = vertPosP[p0[i]]; - qRL[k] = glm::vec3(pRL[k].x, yz01); - ++k; - } - } - } - - const int q0[2] = {halfedgeQ[q1].startVert, halfedgeQ[q1].endVert}; - for (int i : {0, 1}) { - const auto syz10 = Shadow01(q0[i], p1, vertPosQ, vertPosP, halfedgeP, - expandP, normalP, true); - const int s10 = syz10.first; - const glm::vec2 yz10 = syz10.second; - // If the value is NaN, then these do not overlap. - if (isfinite(yz10[0])) { - s11 += s10 * (i == 0 ? -1 : 1); - if (k < 2 && (k == 0 || (s10 != 0) != shadows)) { - shadows = s10 != 0; - qRL[k] = vertPosQ[q0[i]]; - pRL[k] = glm::vec3(qRL[k].x, yz10); - ++k; - } - } - } - - if (s11 == 0) { // No intersection - xyzz11 = glm::vec4(NAN); - } else { -#ifdef MANIFOLD_DEBUG - // Assert left and right were both found - if (k != 2) { - printf("k = %d\n", k); - } -#endif - xyzz11 = Intersect(pRL[0], pRL[1], qRL[0], qRL[1]); - - const int p1s = halfedgeP[p1].startVert; - const int p1e = halfedgeP[p1].endVert; - glm::vec3 diff = vertPosP[p1s] - glm::vec3(xyzz11); - const float start2 = glm::dot(diff, diff); - diff = vertPosP[p1e] - glm::vec3(xyzz11); - const float end2 = glm::dot(diff, diff); - const float dir = start2 < end2 ? normalP[p1s].z : normalP[p1e].z; - - if (!Shadows(xyzz11.z, xyzz11.w, expandP * dir)) s11 = 0; - } - } -}; - -std::tuple, VecDH> Shadow11(SparseIndices &p1q1, - const Manifold::Impl &inP, - const Manifold::Impl &inQ, - float expandP, - ExecutionPolicy policy) { - VecDH s11(p1q1.size()); - VecDH xyzz11(p1q1.size()); - - for_each_n(policy, - zip(xyzz11.begin(), s11.begin(), p1q1.begin(0), p1q1.begin(1)), - p1q1.size(), - Kernel11({inP.vertPos_.cptrD(), inQ.vertPos_.cptrD(), - inP.halfedge_.cptrD(), inQ.halfedge_.cptrD(), expandP, - inP.vertNormal_.cptrD()})); - - p1q1.KeepFinite(xyzz11, s11); - - return std::make_tuple(s11, xyzz11); -}; - -struct Kernel02 { - const glm::vec3 *vertPosP; - const Halfedge *halfedgeQ; - const glm::vec3 *vertPosQ; - const bool forward; - const float expandP; - const glm::vec3 *vertNormalP; - - __host__ __device__ void operator()( - thrust::tuple inout) { - int &s02 = thrust::get<0>(inout); - float &z02 = thrust::get<1>(inout); - const int p0 = thrust::get<2>(inout); - const int q2 = thrust::get<3>(inout); - - // For yzzLR[k], k==0 is the left and k==1 is the right. - int k = 0; - glm::vec3 yzzRL[2]; - // Either the left or right must shadow, but not both. This ensures the - // intersection is between the left and right. - bool shadows = false; - int closestVert = -1; - float minMetric = std::numeric_limits::infinity(); - s02 = 0; - - const glm::vec3 posP = vertPosP[p0]; - for (const int i : {0, 1, 2}) { - const int q1 = 3 * q2 + i; - const Halfedge edge = halfedgeQ[q1]; - const int q1F = edge.IsForward() ? q1 : edge.pairedHalfedge; - - if (!forward) { - const int qVert = halfedgeQ[q1F].startVert; - const glm::vec3 diff = posP - vertPosQ[qVert]; - const float metric = glm::dot(diff, diff); - if (metric < minMetric) { - minMetric = metric; - closestVert = qVert; - } - } - - const auto syz01 = Shadow01(p0, q1F, vertPosP, vertPosQ, halfedgeQ, - expandP, vertNormalP, !forward); - const int s01 = syz01.first; - const glm::vec2 yz01 = syz01.second; - // If the value is NaN, then these do not overlap. - if (isfinite(yz01[0])) { - s02 += s01 * (forward == edge.IsForward() ? -1 : 1); - if (k < 2 && (k == 0 || (s01 != 0) != shadows)) { - shadows = s01 != 0; - yzzRL[k++] = glm::vec3(yz01[0], yz01[1], yz01[1]); - } - } - } - - if (s02 == 0) { // No intersection - z02 = NAN; - } else { -#ifdef MANIFOLD_DEBUG - // Assert left and right were both found - if (k != 2) { - printf("k = %d\n", k); - } -#endif - glm::vec3 vertPos = vertPosP[p0]; - z02 = Interpolate(yzzRL[0], yzzRL[1], vertPos.y)[1]; - if (forward) { - if (!Shadows(vertPos.z, z02, expandP * vertNormalP[p0].z)) s02 = 0; - } else { - // ASSERT(closestVert != -1, topologyErr, "No closest vert"); - if (!Shadows(z02, vertPos.z, expandP * vertNormalP[closestVert].z)) - s02 = 0; - } - } - } -}; - -std::tuple, VecDH> Shadow02(const Manifold::Impl &inP, - const Manifold::Impl &inQ, - SparseIndices &p0q2, bool forward, - float expandP, - ExecutionPolicy policy) { - VecDH s02(p0q2.size()); - VecDH z02(p0q2.size()); - - auto vertNormalP = - forward ? inP.vertNormal_.cptrD() : inQ.vertNormal_.cptrD(); - for_each_n( - policy, - zip(s02.begin(), z02.begin(), p0q2.begin(!forward), p0q2.begin(forward)), - p0q2.size(), - Kernel02({inP.vertPos_.cptrD(), inQ.halfedge_.cptrD(), - inQ.vertPos_.cptrD(), forward, expandP, vertNormalP})); - - p0q2.KeepFinite(z02, s02); - - return std::make_tuple(s02, z02); -}; - -struct Kernel12 { - const thrust::pair p0q2; - const int *s02; - const float *z02; - const int size02; - const thrust::pair p1q1; - const int *s11; - const glm::vec4 *xyzz11; - const int size11; - const Halfedge *halfedgesP; - const Halfedge *halfedgesQ; - const glm::vec3 *vertPosP; - const bool forward; - - __host__ __device__ void operator()( - thrust::tuple inout) { - int &x12 = thrust::get<0>(inout); - glm::vec3 &v12 = thrust::get<1>(inout); - const int p1 = thrust::get<2>(inout); - const int q2 = thrust::get<3>(inout); - - // For xzyLR-[k], k==0 is the left and k==1 is the right. - int k = 0; - glm::vec3 xzyLR0[2]; - glm::vec3 xzyLR1[2]; - // Either the left or right must shadow, but not both. This ensures the - // intersection is between the left and right. - bool shadows = false; - x12 = 0; - - const Halfedge edge = halfedgesP[p1]; - - for (int vert : {edge.startVert, edge.endVert}) { - const auto key = - forward ? thrust::make_pair(vert, q2) : thrust::make_pair(q2, vert); - const int idx = BinarySearch(p0q2, size02, key); - if (idx != -1) { - const int s = s02[idx]; - x12 += s * ((vert == edge.startVert) == forward ? 1 : -1); - if (k < 2 && (k == 0 || (s != 0) != shadows)) { - shadows = s != 0; - xzyLR0[k] = vertPosP[vert]; - thrust::swap(xzyLR0[k].y, xzyLR0[k].z); - xzyLR1[k] = xzyLR0[k]; - xzyLR1[k][1] = z02[idx]; - k++; - } - } - } - - for (const int i : {0, 1, 2}) { - const int q1 = 3 * q2 + i; - const Halfedge edge = halfedgesQ[q1]; - const int q1F = edge.IsForward() ? q1 : edge.pairedHalfedge; - const auto key = - forward ? thrust::make_pair(p1, q1F) : thrust::make_pair(q1F, p1); - const int idx = BinarySearch(p1q1, size11, key); - if (idx != -1) { // s is implicitly zero for anything not found - const int s = s11[idx]; - x12 -= s * (edge.IsForward() ? 1 : -1); - if (k < 2 && (k == 0 || (s != 0) != shadows)) { - shadows = s != 0; - const glm::vec4 xyzz = xyzz11[idx]; - xzyLR0[k][0] = xyzz.x; - xzyLR0[k][1] = xyzz.z; - xzyLR0[k][2] = xyzz.y; - xzyLR1[k] = xzyLR0[k]; - xzyLR1[k][1] = xyzz.w; - if (!forward) thrust::swap(xzyLR0[k][1], xzyLR1[k][1]); - k++; - } - } - } - - if (x12 == 0) { // No intersection - v12 = glm::vec3(NAN); - } else { -#ifdef MANIFOLD_DEBUG - // Assert left and right were both found - if (k != 2) { - printf("k = %d\n", k); - } -#endif - const glm::vec4 xzyy = - Intersect(xzyLR0[0], xzyLR0[1], xzyLR1[0], xzyLR1[1]); - v12.x = xzyy[0]; - v12.y = xzyy[2]; - v12.z = xzyy[1]; - } - } -}; - -std::tuple, VecDH> Intersect12( - const Manifold::Impl &inP, const Manifold::Impl &inQ, const VecDH &s02, - const SparseIndices &p0q2, const VecDH &s11, const SparseIndices &p1q1, - const VecDH &z02, const VecDH &xyzz11, - SparseIndices &p1q2, bool forward, ExecutionPolicy policy) { - VecDH x12(p1q2.size()); - VecDH v12(p1q2.size()); - - for_each_n( - policy, - zip(x12.begin(), v12.begin(), p1q2.begin(!forward), p1q2.begin(forward)), - p1q2.size(), - Kernel12({p0q2.ptrDpq(), s02.ptrD(), z02.cptrD(), p0q2.size(), - p1q1.ptrDpq(), s11.ptrD(), xyzz11.cptrD(), p1q1.size(), - inP.halfedge_.cptrD(), inQ.halfedge_.cptrD(), - inP.vertPos_.cptrD(), forward})); - - p1q2.KeepFinite(v12, x12); - - return std::make_tuple(x12, v12); -}; - -VecDH Winding03(const Manifold::Impl &inP, SparseIndices &p0q2, - VecDH &s02, bool reverse, ExecutionPolicy policy) { - // verts that are not shadowed (not in p0q2) have winding number zero. - VecDH w03(inP.NumVert(), 0); - - if (!is_sorted(policy, p0q2.begin(reverse), p0q2.end(reverse))) - sort_by_key(policy, p0q2.begin(reverse), p0q2.end(reverse), s02.begin()); - VecDH w03val(w03.size()); - VecDH w03vert(w03.size()); - // sum known s02 values into w03 (winding number) - auto endPair = reduce_by_key< - thrust::pair>( - policy, p0q2.begin(reverse), p0q2.end(reverse), s02.begin(), - w03vert.begin(), w03val.begin()); - scatter(policy, w03val.begin(), endPair.second, w03vert.begin(), w03.begin()); - - if (reverse) - transform(policy, w03.begin(), w03.end(), w03.begin(), - thrust::negate()); - return w03; -}; -} // namespace - -namespace manifold { -Boolean3::Boolean3(const Manifold::Impl &inP, const Manifold::Impl &inQ, - Manifold::OpType op) - : inP_(inP), - inQ_(inQ), - expandP_(op == Manifold::OpType::ADD ? 1.0 : -1.0), - policy_(autoPolicy(glm::max(inP.NumEdge(), inQ.NumEdge()))) { - // Symbolic perturbation: - // Union -> expand inP - // Difference, Intersection -> contract inP - -#ifdef MANIFOLD_DEBUG - Timer broad; - broad.Start(); -#endif - - if (inP.IsEmpty() || inQ.IsEmpty() || !inP.bBox_.DoesOverlap(inQ.bBox_)) { - PRINT("No overlap, early out"); - w03_.resize(inP.NumVert(), 0); - w30_.resize(inQ.NumVert(), 0); - return; - } - - // Level 3 - // Find edge-triangle overlaps (broad phase) - p1q2_ = inQ_.EdgeCollisions(inP_); - p2q1_ = inP_.EdgeCollisions(inQ_); - - policy_ = autoPolicy(glm::max(p1q2_.size(), p2q1_.size())); - p1q2_.Sort(policy_); - PRINT("p1q2 size = " << p1q2_.size()); - - p2q1_.SwapPQ(); - p2q1_.Sort(policy_); - PRINT("p2q1 size = " << p2q1_.size()); - - // Level 2 - // Find vertices that overlap faces in XY-projection - SparseIndices p0q2 = inQ.VertexCollisionsZ(inP.vertPos_); - p0q2.Sort(policy_); - PRINT("p0q2 size = " << p0q2.size()); - - SparseIndices p2q0 = inP.VertexCollisionsZ(inQ.vertPos_); - p2q0.SwapPQ(); - p2q0.Sort(policy_); - PRINT("p2q0 size = " << p2q0.size()); - - // Find involved edge pairs from Level 3 - SparseIndices p1q1 = Filter11(inP_, inQ_, p1q2_, p2q1_, policy_); - PRINT("p1q1 size = " << p1q1.size()); - -#ifdef MANIFOLD_DEBUG - broad.Stop(); - Timer intersections; - intersections.Start(); -#endif - - // Level 2 - // Build up XY-projection intersection of two edges, including the z-value for - // each edge, keeping only those whose intersection exists. - VecDH s11; - VecDH xyzz11; - std::tie(s11, xyzz11) = Shadow11(p1q1, inP, inQ, expandP_, policy_); - PRINT("s11 size = " << s11.size()); - - // Build up Z-projection of vertices onto triangles, keeping only those that - // fall inside the triangle. - VecDH s02; - VecDH z02; - std::tie(s02, z02) = Shadow02(inP, inQ, p0q2, true, expandP_, policy_); - PRINT("s02 size = " << s02.size()); - - VecDH s20; - VecDH z20; - std::tie(s20, z20) = Shadow02(inQ, inP, p2q0, false, expandP_, policy_); - PRINT("s20 size = " << s20.size()); - - // Level 3 - // Build up the intersection of the edges and triangles, keeping only those - // that intersect, and record the direction the edge is passing through the - // triangle. - std::tie(x12_, v12_) = Intersect12(inP, inQ, s02, p0q2, s11, p1q1, z02, - xyzz11, p1q2_, true, policy_); - PRINT("x12 size = " << x12_.size()); - - std::tie(x21_, v21_) = Intersect12(inQ, inP, s20, p2q0, s11, p1q1, z20, - xyzz11, p2q1_, false, policy_); - PRINT("x21 size = " << x21_.size()); - - // Sum up the winding numbers of all vertices. - w03_ = Winding03(inP, p0q2, s02, false, policy_); - - w30_ = Winding03(inQ, p2q0, s20, true, policy_); - -#ifdef MANIFOLD_DEBUG - intersections.Stop(); - - if (ManifoldParams().verbose) { - broad.Print("Broad phase"); - intersections.Print("Intersections"); - MemUsage(); - } -#endif -} -} // namespace manifold diff --git a/IfcPlusPlus/src/external/manifold/src/boolean3.h b/IfcPlusPlus/src/external/manifold/src/boolean3.h deleted file mode 100644 index 7a4f864ab..000000000 --- a/IfcPlusPlus/src/external/manifold/src/boolean3.h +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2020 The Manifold Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once -#include "impl.h" - -#ifdef MANIFOLD_DEBUG -#define PRINT(msg) \ - if (ManifoldParams().verbose) std::cout << msg << std::endl; -#else -#define PRINT(msg) -#endif - -/** - * The notation in these files is abbreviated due to the complexity of the - * functions involved. The key is that the input manifolds are P and Q, while - * the output is R, and these letters in both upper and lower case refer to - * these objects. Operations are based on dimensionality: vert: 0, edge: 1, - * face: 2, solid: 3. X denotes a winding-number type quantity from the source - * paper of this algorithm, while S is closely related but includes only the - * subset of X values which "shadow" (are on the correct side of). - * - * Nearly everything here are sparse arrays, where for instance each pair in - * p2q1 refers to a face index of P interacting with a halfedge index of Q. - * Adjacent arrays like x21 refer to the values of X corresponding to each - * sparse index pair. - * - * Note many functions are designed to work symmetrically, for instance for both - * p2q1 and p1q2. Inside of these functions P and Q are marked as though the - * function is forwards, but it may include a Boolean "reverse" that indicates P - * and Q have been swapped. - */ - -namespace manifold { - -/** @ingroup Private */ -class Boolean3 { - public: - Boolean3(const Manifold::Impl& inP, const Manifold::Impl& inQ, - Manifold::OpType op); - Manifold::Impl Result(Manifold::OpType op) const; - - private: - const Manifold::Impl &inP_, &inQ_; - const float expandP_; - SparseIndices p1q2_, p2q1_; - VecDH x12_, x21_, w03_, w30_; - VecDH v12_, v21_; - ExecutionPolicy policy_; -}; -} // namespace manifold diff --git a/IfcPlusPlus/src/external/manifold/src/boolean_result.cpp b/IfcPlusPlus/src/external/manifold/src/boolean_result.cpp deleted file mode 100644 index 1f039f7a8..000000000 --- a/IfcPlusPlus/src/external/manifold/src/boolean_result.cpp +++ /dev/null @@ -1,700 +0,0 @@ -// Copyright 2021 The Manifold Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include - -#include "boolean3.h" -#include "par.h" -#include "polygon.h" - -using namespace manifold; -using namespace thrust::placeholders; - -namespace { - -struct AbsSum : public thrust::binary_function { - __host__ __device__ int operator()(int a, int b) { return abs(a) + abs(b); } -}; - -struct DuplicateVerts { - glm::vec3 *vertPosR; - - __host__ __device__ void operator()(thrust::tuple in) { - int inclusion = abs(thrust::get<0>(in)); - int vertR = thrust::get<1>(in); - glm::vec3 vertPosP = thrust::get<2>(in); - - for (int i = 0; i < inclusion; ++i) { - vertPosR[vertR + i] = vertPosP; - } - } -}; - -struct CountVerts { - int *count; - const int *inclusion; - - __host__ __device__ void operator()(const Halfedge &edge) { - AtomicAdd(count[edge.face], glm::abs(inclusion[edge.startVert])); - } -}; - -struct CountNewVerts { - int *countP; - int *countQ; - const Halfedge *halfedges; - - __host__ __device__ void operator()(thrust::tuple in) { - int edgeP = thrust::get<0>(in); - int faceQ = thrust::get<1>(in); - int inclusion = glm::abs(thrust::get<2>(in)); - - AtomicAdd(countQ[faceQ], inclusion); - const Halfedge half = halfedges[edgeP]; - AtomicAdd(countP[half.face], inclusion); - AtomicAdd(countP[halfedges[half.pairedHalfedge].face], inclusion); - } -}; - -struct NotZero : public thrust::unary_function { - __host__ __device__ int operator()(int x) const { return x > 0 ? 1 : 0; } -}; - -std::tuple, VecDH> SizeOutput( - Manifold::Impl &outR, const Manifold::Impl &inP, const Manifold::Impl &inQ, - const VecDH &i03, const VecDH &i30, const VecDH &i12, - const VecDH &i21, const SparseIndices &p1q2, const SparseIndices &p2q1, - bool invertQ, ExecutionPolicy policy) { - VecDH sidesPerFacePQ(inP.NumTri() + inQ.NumTri(), 0); - auto sidesPerFaceP = sidesPerFacePQ.ptrD(); - auto sidesPerFaceQ = sidesPerFacePQ.ptrD() + inP.NumTri(); - - for_each(policy, inP.halfedge_.begin(), inP.halfedge_.end(), - CountVerts({sidesPerFaceP, i03.cptrD()})); - for_each(policy, inQ.halfedge_.begin(), inQ.halfedge_.end(), - CountVerts({sidesPerFaceQ, i30.cptrD()})); - for_each_n( - policy, zip(p1q2.begin(0), p1q2.begin(1), i12.begin()), i12.size(), - CountNewVerts({sidesPerFaceP, sidesPerFaceQ, inP.halfedge_.cptrD()})); - for_each_n( - policy, zip(p2q1.begin(1), p2q1.begin(0), i21.begin()), i21.size(), - CountNewVerts({sidesPerFaceQ, sidesPerFaceP, inQ.halfedge_.cptrD()})); - - VecDH facePQ2R(inP.NumTri() + inQ.NumTri() + 1, 0); - auto keepFace = - thrust::make_transform_iterator(sidesPerFacePQ.begin(), NotZero()); - inclusive_scan(policy, keepFace, keepFace + sidesPerFacePQ.size(), - facePQ2R.begin() + 1); - int numFaceR = facePQ2R.back(); - facePQ2R.resize(inP.NumTri() + inQ.NumTri()); - - outR.faceNormal_.resize(numFaceR); - auto next = copy_if( - policy, inP.faceNormal_.begin(), inP.faceNormal_.end(), keepFace, - outR.faceNormal_.begin(), thrust::identity()); - if (invertQ) { - auto start = thrust::make_transform_iterator(inQ.faceNormal_.begin(), - thrust::negate()); - auto end = thrust::make_transform_iterator(inQ.faceNormal_.end(), - thrust::negate()); - copy_if(policy, start, end, - keepFace + inP.NumTri(), next, - thrust::identity()); - } else { - copy_if( - policy, inQ.faceNormal_.begin(), inQ.faceNormal_.end(), - keepFace + inP.NumTri(), next, thrust::identity()); - } - - auto newEnd = remove( - policy, sidesPerFacePQ.begin(), sidesPerFacePQ.end(), 0); - VecDH faceEdge(newEnd - sidesPerFacePQ.begin() + 1, 0); - inclusive_scan(policy, sidesPerFacePQ.begin(), newEnd, faceEdge.begin() + 1); - outR.halfedge_.resize(faceEdge.back()); - - return std::make_tuple(faceEdge, facePQ2R); -} - -struct EdgePos { - int vert; - float edgePos; - bool isStart; -}; - -void AddNewEdgeVerts( - std::map> &edgesP, - std::map, std::vector> &edgesNew, - const SparseIndices &p1q2, const VecDH &i12, const VecDH &v12R, - const VecDH &halfedgeP, bool forward) { - // For each edge of P that intersects a face of Q (p1q2), add this vertex to - // P's corresponding edge vector and to the two new edges, which are - // intersections between the face of Q and the two faces of P attached to the - // edge. The direction and duplicity are given by i12, while v12R remaps to - // the output vert index. When forward is false, all is reversed. - const VecDH &p1 = p1q2.Get(!forward); - const VecDH &q2 = p1q2.Get(forward); - for (int i = 0; i < p1q2.size(); ++i) { - const int edgeP = p1[i]; - const int faceQ = q2[i]; - const int vert = v12R[i]; - const int inclusion = i12[i]; - - auto &edgePosP = edgesP[edgeP]; - - Halfedge halfedge = halfedgeP[edgeP]; - std::pair key = {halfedgeP[halfedge.pairedHalfedge].face, faceQ}; - if (!forward) std::swap(key.first, key.second); - auto &edgePosRight = edgesNew[key]; - - key = {halfedge.face, faceQ}; - if (!forward) std::swap(key.first, key.second); - auto &edgePosLeft = edgesNew[key]; - - EdgePos edgePos = {vert, 0.0f, inclusion < 0}; - EdgePos edgePosRev = edgePos; - edgePosRev.isStart = !edgePos.isStart; - - for (int j = 0; j < glm::abs(inclusion); ++j) { - edgePosP.push_back(edgePos); - edgePosRight.push_back(forward ? edgePos : edgePosRev); - edgePosLeft.push_back(forward ? edgePosRev : edgePos); - ++edgePos.vert; - ++edgePosRev.vert; - } - } -} - -std::vector PairUp(std::vector &edgePos) { - // Pair start vertices with end vertices to form edges. The choice of pairing - // is arbitrary for the manifoldness guarantee, but must be ordered to be - // geometrically valid. If the order does not go start-end-start-end... then - // the input and output are not geometrically valid and this algorithm becomes - // a heuristic. - ASSERT(edgePos.size() % 2 == 0, topologyErr, - "Non-manifold edge! Not an even number of points."); - int nEdges = edgePos.size() / 2; - auto middle = std::partition(edgePos.begin(), edgePos.end(), - [](EdgePos x) { return x.isStart; }); - ASSERT(middle - edgePos.begin() == nEdges, topologyErr, "Non-manifold edge!"); - auto cmp = [](EdgePos a, EdgePos b) { return a.edgePos < b.edgePos; }; - std::sort(edgePos.begin(), middle, cmp); - std::sort(middle, edgePos.end(), cmp); - std::vector edges; - for (int i = 0; i < nEdges; ++i) - edges.push_back({edgePos[i].vert, edgePos[i + nEdges].vert, -1, -1}); - return edges; -} - -// A Ref carries the reference of a halfedge's startVert back to the input -// manifolds. PQ is 0 if the halfedge comes from triangle tri of P, and 1 for Q. -// vert is 0, 1, or 2 to denote which vertex of tri it is, and -1 if it is new. -struct Ref { - int PQ, tri, vert; -}; - -void AppendPartialEdges(Manifold::Impl &outR, VecDH &wholeHalfedgeP, - VecDH &facePtrR, - std::map> &edgesP, - VecDH &halfedgeRef, const Manifold::Impl &inP, - const VecDH &i03, const VecDH &vP2R, - const VecDH::IterC faceP2R, bool forward) { - // Each edge in the map is partially retained; for each of these, look up - // their original verts and include them based on their winding number (i03), - // while remapping them to the output using vP2R. Use the verts position - // projected along the edge vector to pair them up, then distribute these - // edges to their faces. - VecDH &halfedgeR = outR.halfedge_; - const VecDH &vertPosP = inP.vertPos_; - const VecDH &halfedgeP = inP.halfedge_; - - for (auto &value : edgesP) { - const int edgeP = value.first; - std::vector &edgePosP = value.second; - - const Halfedge &halfedge = halfedgeP[edgeP]; - wholeHalfedgeP[edgeP] = false; - wholeHalfedgeP[halfedge.pairedHalfedge] = false; - - const int vStart = halfedge.startVert; - const int vEnd = halfedge.endVert; - const glm::vec3 edgeVec = vertPosP[vEnd] - vertPosP[vStart]; - // Fill in the edge positions of the old points. - for (EdgePos &edge : edgePosP) { - edge.edgePos = glm::dot(outR.vertPos_[edge.vert], edgeVec); - } - - int inclusion = i03[vStart]; - bool reversed = inclusion < 0; - EdgePos edgePos = {vP2R[vStart], - glm::dot(outR.vertPos_[vP2R[vStart]], edgeVec), - inclusion > 0}; - for (int j = 0; j < glm::abs(inclusion); ++j) { - edgePosP.push_back(edgePos); - ++edgePos.vert; - } - - inclusion = i03[vEnd]; - reversed |= inclusion < 0; - edgePos = {vP2R[vEnd], glm::dot(outR.vertPos_[vP2R[vEnd]], edgeVec), - inclusion < 0}; - for (int j = 0; j < glm::abs(inclusion); ++j) { - edgePosP.push_back(edgePos); - ++edgePos.vert; - } - - // sort edges into start/end pairs along length - std::vector edges = PairUp(edgePosP); - - // add halfedges to result - const int faceLeftP = halfedge.face; - const int faceLeft = faceP2R[faceLeftP]; - const int faceRightP = halfedgeP[halfedge.pairedHalfedge].face; - const int faceRight = faceP2R[faceRightP]; - // Negative inclusion means the halfedges are reversed, which means our - // reference is now to the endVert instead of the startVert, which is one - // position advanced CCW. This is only valid if this is a retained vert; it - // will be ignored later if the vert is new. - const Ref forwardRef = {forward ? 0 : 1, faceLeftP, - (edgeP + (reversed ? 1 : 0)) % 3}; - const Ref backwardRef = { - forward ? 0 : 1, faceRightP, - (halfedge.pairedHalfedge + (reversed ? 1 : 0)) % 3}; - - for (Halfedge e : edges) { - const int forwardEdge = facePtrR[faceLeft]++; - const int backwardEdge = facePtrR[faceRight]++; - - e.face = faceLeft; - e.pairedHalfedge = backwardEdge; - halfedgeR[forwardEdge] = e; - halfedgeRef[forwardEdge] = forwardRef; - - std::swap(e.startVert, e.endVert); - e.face = faceRight; - e.pairedHalfedge = forwardEdge; - halfedgeR[backwardEdge] = e; - halfedgeRef[backwardEdge] = backwardRef; - } - } -} - -void AppendNewEdges( - Manifold::Impl &outR, VecDH &facePtrR, - std::map, std::vector> &edgesNew, - VecDH &halfedgeRef, const VecDH &facePQ2R, const int numFaceP) { - // Pair up each edge's verts and distribute to faces based on indices in key. - VecDH &halfedgeR = outR.halfedge_; - VecDH &vertPosR = outR.vertPos_; - - for (auto &value : edgesNew) { - const int faceP = value.first.first; - const int faceQ = value.first.second; - std::vector &edgePos = value.second; - - Box bbox; - for (auto edge : edgePos) { - bbox.Union(vertPosR[edge.vert]); - } - const glm::vec3 size = bbox.Size(); - // Order the points along their longest dimension. - const int i = (size.x > size.y && size.x > size.z) ? 0 - : size.y > size.z ? 1 - : 2; - for (auto &edge : edgePos) { - edge.edgePos = vertPosR[edge.vert][i]; - } - - // sort edges into start/end pairs along length. - std::vector edges = PairUp(edgePos); - - // add halfedges to result - const int faceLeft = facePQ2R[faceP]; - const int faceRight = facePQ2R[numFaceP + faceQ]; - const Ref forwardRef = {0, faceP, -4}; - const Ref backwardRef = {1, faceQ, -4}; - for (Halfedge e : edges) { - const int forwardEdge = facePtrR[faceLeft]++; - const int backwardEdge = facePtrR[faceRight]++; - - e.face = faceLeft; - e.pairedHalfedge = backwardEdge; - halfedgeR[forwardEdge] = e; - halfedgeRef[forwardEdge] = forwardRef; - - std::swap(e.startVert, e.endVert); - e.face = faceRight; - e.pairedHalfedge = forwardEdge; - halfedgeR[backwardEdge] = e; - halfedgeRef[backwardEdge] = backwardRef; - } - } -} - -struct DuplicateHalfedges { - Halfedge *halfedgesR; - Ref *halfedgeRef; - int *facePtr; - const Halfedge *halfedgesP; - const int *i03; - const int *vP2R; - const int *faceP2R; - const bool forward; - - __host__ __device__ void operator()(thrust::tuple in) { - if (!thrust::get<0>(in)) return; - Halfedge halfedge = thrust::get<1>(in); - if (!halfedge.IsForward()) return; - const int edgeP = thrust::get<2>(in); - - const int inclusion = i03[halfedge.startVert]; - if (inclusion == 0) return; - if (inclusion < 0) { // reverse - int tmp = halfedge.startVert; - halfedge.startVert = halfedge.endVert; - halfedge.endVert = tmp; - } - halfedge.startVert = vP2R[halfedge.startVert]; - halfedge.endVert = vP2R[halfedge.endVert]; - const int faceLeftP = halfedge.face; - halfedge.face = faceP2R[faceLeftP]; - const int faceRightP = halfedgesP[halfedge.pairedHalfedge].face; - const int faceRight = faceP2R[faceRightP]; - // Negative inclusion means the halfedges are reversed, which means our - // reference is now to the endVert instead of the startVert, which is one - // position advanced CCW. - const Ref forwardRef = {forward ? 0 : 1, faceLeftP, - (edgeP + (inclusion < 0 ? 1 : 0)) % 3}; - const Ref backwardRef = { - forward ? 0 : 1, faceRightP, - (halfedge.pairedHalfedge + (inclusion < 0 ? 1 : 0)) % 3}; - - for (int i = 0; i < glm::abs(inclusion); ++i) { - int forwardEdge = AtomicAdd(facePtr[halfedge.face], 1); - int backwardEdge = AtomicAdd(facePtr[faceRight], 1); - halfedge.pairedHalfedge = backwardEdge; - - halfedgesR[forwardEdge] = halfedge; - halfedgesR[backwardEdge] = {halfedge.endVert, halfedge.startVert, - forwardEdge, faceRight}; - halfedgeRef[forwardEdge] = forwardRef; - halfedgeRef[backwardEdge] = backwardRef; - - ++halfedge.startVert; - ++halfedge.endVert; - } - } -}; - -void AppendWholeEdges(Manifold::Impl &outR, VecDH &facePtrR, - VecDH &halfedgeRef, const Manifold::Impl &inP, - const VecDH wholeHalfedgeP, const VecDH &i03, - const VecDH &vP2R, const int *faceP2R, bool forward, - ExecutionPolicy policy) { - for_each_n(policy, - zip(wholeHalfedgeP.begin(), inP.halfedge_.begin(), countAt(0)), - inP.halfedge_.size(), - DuplicateHalfedges({outR.halfedge_.ptrD(), halfedgeRef.ptrD(), - facePtrR.ptrD(), inP.halfedge_.cptrD(), - i03.cptrD(), vP2R.cptrD(), faceP2R, forward})); -} - -struct CreateBarycentric { - glm::vec3 *barycentricR; - BaryRef *faceRef; - int *idx; - - const int offsetQ; - const int firstNewVert; - const glm::vec3 *vertPosR; - const glm::vec3 *vertPosP; - const glm::vec3 *vertPosQ; - const Halfedge *halfedgeP; - const Halfedge *halfedgeQ; - const BaryRef *triBaryP; - const BaryRef *triBaryQ; - const glm::vec3 *barycentricP; - const glm::vec3 *barycentricQ; - const bool invertQ; - const float precision; - - __host__ __device__ void operator()( - thrust::tuple inOut) { - int &halfedgeBary = thrust::get<0>(inOut); - const Ref halfedgeRef = thrust::get<1>(inOut); - const Halfedge halfedgeR = thrust::get<2>(inOut); - - const glm::vec3 *barycentric = - halfedgeRef.PQ == 0 ? barycentricP : barycentricQ; - const int tri = halfedgeRef.tri; - const BaryRef oldRef = halfedgeRef.PQ == 0 ? triBaryP[tri] : triBaryQ[tri]; - - faceRef[halfedgeR.face] = oldRef; - - if (halfedgeRef.PQ == 1) { - // Mark the meshID as coming from Q - faceRef[halfedgeR.face].meshID += offsetQ; - } - - if (halfedgeR.startVert < firstNewVert) { // retained vert - int i = halfedgeRef.vert; - const int bary = oldRef.vertBary[i]; - if (bary < 0) { - halfedgeBary = bary; - } else { - halfedgeBary = AtomicAdd(*idx, 1); - barycentricR[halfedgeBary] = barycentric[bary]; - } - } else { // new vert - halfedgeBary = AtomicAdd(*idx, 1); - - const glm::vec3 *vertPos = halfedgeRef.PQ == 0 ? vertPosP : vertPosQ; - const Halfedge *halfedge = halfedgeRef.PQ == 0 ? halfedgeP : halfedgeQ; - - glm::mat3 triPos; - for (int i : {0, 1, 2}) - triPos[i] = vertPos[halfedge[3 * tri + i].startVert]; - - glm::mat3 uvwOldTri; - for (int i : {0, 1, 2}) - uvwOldTri[i] = UVW(oldRef.vertBary[i], barycentric); - - const glm::vec3 uvw = - GetBarycentric(vertPosR[halfedgeR.startVert], triPos, precision); - barycentricR[halfedgeBary] = uvwOldTri * uvw; - } - } -}; - -std::pair, VecDH> CalculateMeshRelation( - Manifold::Impl &outR, const VecDH &halfedgeRef, - const Manifold::Impl &inP, const Manifold::Impl &inQ, int firstNewVert, - int numFaceR, bool invertQ, ExecutionPolicy policy) { - outR.meshRelation_.barycentric.resize(outR.halfedge_.size()); - VecDH faceRef(numFaceR); - VecDH halfedgeBary(halfedgeRef.size()); - - const int offsetQ = Manifold::Impl::meshIDCounter_; - VecDH idx(1, 0); - for_each_n( - policy, - zip(halfedgeBary.begin(), halfedgeRef.begin(), outR.halfedge_.cbegin()), - halfedgeRef.size(), - CreateBarycentric( - {outR.meshRelation_.barycentric.ptrD(), faceRef.ptrD(), idx.ptrD(), - offsetQ, firstNewVert, outR.vertPos_.cptrD(), inP.vertPos_.cptrD(), - inQ.vertPos_.cptrD(), inP.halfedge_.cptrD(), inQ.halfedge_.cptrD(), - inP.meshRelation_.triBary.cptrD(), inQ.meshRelation_.triBary.cptrD(), - inP.meshRelation_.barycentric.cptrD(), - inQ.meshRelation_.barycentric.cptrD(), invertQ, outR.precision_})); - outR.meshRelation_.barycentric.resize(idx[0]); - - return std::make_pair(faceRef, halfedgeBary); -} -} // namespace - -namespace manifold { - -Manifold::Impl Boolean3::Result(Manifold::OpType op) const { -#ifdef MANIFOLD_DEBUG - Timer assemble; - assemble.Start(); -#endif - - ASSERT((expandP_ > 0) == (op == Manifold::OpType::ADD), logicErr, - "Result op type not compatible with constructor op type."); - const int c1 = op == Manifold::OpType::INTERSECT ? 0 : 1; - const int c2 = op == Manifold::OpType::ADD ? 1 : 0; - const int c3 = op == Manifold::OpType::INTERSECT ? 1 : -1; - - if (w03_.size() == 0) { - if (w30_.size() != 0 && op == Manifold::OpType::ADD) { - return inQ_; - } - return Manifold::Impl(); - } else if (w30_.size() == 0) { - if (op == Manifold::OpType::INTERSECT) { - return Manifold::Impl(); - } - return inP_; - } - - const bool invertQ = op == Manifold::OpType::SUBTRACT; - - // Convert winding numbers to inclusion values based on operation type. - VecDH i12(x12_.size()); - VecDH i21(x21_.size()); - VecDH i03(w03_.size()); - VecDH i30(w30_.size()); - - transform(policy_, x12_.begin(), x12_.end(), i12.begin(), c3 * _1); - transform(policy_, x21_.begin(), x21_.end(), i21.begin(), c3 * _1); - transform(policy_, w03_.begin(), w03_.end(), i03.begin(), c1 + c3 * _1); - transform(policy_, w30_.begin(), w30_.end(), i30.begin(), c2 + c3 * _1); - - VecDH vP2R(inP_.NumVert()); - exclusive_scan(policy_, i03.begin(), i03.end(), vP2R.begin(), 0, AbsSum()); - int numVertR = AbsSum()(vP2R.back(), i03.back()); - const int nPv = numVertR; - - VecDH vQ2R(inQ_.NumVert()); - exclusive_scan(policy_, i30.begin(), i30.end(), vQ2R.begin(), numVertR, - AbsSum()); - numVertR = AbsSum()(vQ2R.back(), i30.back()); - const int nQv = numVertR - nPv; - - VecDH v12R(v12_.size()); - if (v12_.size() > 0) { - exclusive_scan(policy_, i12.begin(), i12.end(), v12R.begin(), numVertR, - AbsSum()); - numVertR = AbsSum()(v12R.back(), i12.back()); - } - const int n12 = numVertR - nPv - nQv; - - VecDH v21R(v21_.size()); - if (v21_.size() > 0) { - exclusive_scan(policy_, i21.begin(), i21.end(), v21R.begin(), numVertR, - AbsSum()); - numVertR = AbsSum()(v21R.back(), i21.back()); - } - const int n21 = numVertR - nPv - nQv - n12; - - // Create the output Manifold - Manifold::Impl outR; - outR.meshids = inP_.meshids + inQ_.meshids; - - if (numVertR == 0) return outR; - - outR.precision_ = glm::max(inP_.precision_, inQ_.precision_); - - outR.vertPos_.resize(numVertR); - // Add vertices, duplicating for inclusion numbers not in [-1, 1]. - // Retained vertices from P and Q: - for_each_n(policy_, zip(i03.begin(), vP2R.begin(), inP_.vertPos_.begin()), - inP_.NumVert(), DuplicateVerts({outR.vertPos_.ptrD()})); - for_each_n(policy_, zip(i30.begin(), vQ2R.begin(), inQ_.vertPos_.begin()), - inQ_.NumVert(), DuplicateVerts({outR.vertPos_.ptrD()})); - // New vertices created from intersections: - for_each_n(policy_, zip(i12.begin(), v12R.begin(), v12_.begin()), i12.size(), - DuplicateVerts({outR.vertPos_.ptrD()})); - for_each_n(policy_, zip(i21.begin(), v21R.begin(), v21_.begin()), i21.size(), - DuplicateVerts({outR.vertPos_.ptrD()})); - - PRINT(nPv << " verts from inP"); - PRINT(nQv << " verts from inQ"); - PRINT(n12 << " new verts from edgesP -> facesQ"); - PRINT(n21 << " new verts from facesP -> edgesQ"); - - // Build up new polygonal faces from triangle intersections. At this point the - // calculation switches from parallel to serial. - - // Level 3 - - // This key is the forward halfedge index of P or Q. Only includes intersected - // edges. - std::map> edgesP, edgesQ; - // This key is the face index of - std::map, std::vector> edgesNew; - - AddNewEdgeVerts(edgesP, edgesNew, p1q2_, i12, v12R, inP_.halfedge_, true); - AddNewEdgeVerts(edgesQ, edgesNew, p2q1_, i21, v21R, inQ_.halfedge_, false); - - // Level 4 - VecDH faceEdge; - VecDH facePQ2R; - std::tie(faceEdge, facePQ2R) = SizeOutput( - outR, inP_, inQ_, i03, i30, i12, i21, p1q2_, p2q1_, invertQ, policy_); - - const int numFaceR = faceEdge.size() - 1; - // This gets incremented for each halfedge that's added to a face so that the - // next one knows where to slot in. - VecDH facePtrR = faceEdge; - // Intersected halfedges are marked false. - VecDH wholeHalfedgeP(inP_.halfedge_.size(), true); - VecDH wholeHalfedgeQ(inQ_.halfedge_.size(), true); - // The halfedgeRef contains the data that will become triBary once the faces - // are triangulated. - VecDH halfedgeRef(2 * outR.NumEdge()); - - AppendPartialEdges(outR, wholeHalfedgeP, facePtrR, edgesP, halfedgeRef, inP_, - i03, vP2R, facePQ2R.begin(), true); - AppendPartialEdges(outR, wholeHalfedgeQ, facePtrR, edgesQ, halfedgeRef, inQ_, - i30, vQ2R, facePQ2R.begin() + inP_.NumTri(), false); - - AppendNewEdges(outR, facePtrR, edgesNew, halfedgeRef, facePQ2R, - inP_.NumTri()); - - AppendWholeEdges(outR, facePtrR, halfedgeRef, inP_, wholeHalfedgeP, i03, vP2R, - facePQ2R.cptrD(), true, policy_); - AppendWholeEdges(outR, facePtrR, halfedgeRef, inQ_, wholeHalfedgeQ, i30, vQ2R, - facePQ2R.cptrD() + inP_.NumTri(), false, policy_); - - VecDH faceRef; - VecDH halfedgeBary; - std::tie(faceRef, halfedgeBary) = CalculateMeshRelation( - outR, halfedgeRef, inP_, inQ_, nPv + nQv, numFaceR, invertQ, policy_); - -#ifdef MANIFOLD_DEBUG - assemble.Stop(); - Timer triangulate; - triangulate.Start(); -#endif - - // Level 6 - - if (ManifoldParams().intermediateChecks) - ASSERT(outR.IsManifold(), logicErr, "polygon mesh is not manifold!"); - - outR.Face2Tri(faceEdge, faceRef, halfedgeBary); - -#ifdef MANIFOLD_DEBUG - triangulate.Stop(); - Timer simplify; - simplify.Start(); -#endif - - if (ManifoldParams().intermediateChecks) - ASSERT(outR.IsManifold(), logicErr, "triangulated mesh is not manifold!"); - - outR.SimplifyTopology(); - - if (ManifoldParams().intermediateChecks) - ASSERT(outR.Is2Manifold(), logicErr, "simplified mesh is not 2-manifold!"); - - outR.IncrementMeshIDs(0, outR.NumTri()); - -#ifdef MANIFOLD_DEBUG - simplify.Stop(); - Timer sort; - sort.Start(); -#endif - - outR.Finish(); - -#ifdef MANIFOLD_DEBUG - sort.Stop(); - if (ManifoldParams().verbose) { - assemble.Print("Assembly"); - triangulate.Print("Triangulation"); - simplify.Print("Simplification"); - sort.Print("Sorting"); - std::cout << outR.NumVert() << " verts and " << outR.NumTri() << " tris" - << std::endl; - } -#endif - - return outR; -} - -} // namespace manifold diff --git a/IfcPlusPlus/src/external/manifold/src/collider/CMakeLists.txt b/IfcPlusPlus/src/external/manifold/src/collider/CMakeLists.txt deleted file mode 100644 index db6b8e094..000000000 --- a/IfcPlusPlus/src/external/manifold/src/collider/CMakeLists.txt +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright 2020 The Manifold Authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -project (collider) - -file(GLOB_RECURSE SOURCE_FILES CONFIGURE_DEPENDS *.cpp) -add_library(${PROJECT_NAME} ${SOURCE_FILES}) - -if(MANIFOLD_USE_CUDA) - set_source_files_properties(${SOURCE_FILES} PROPERTIES LANGUAGE CUDA) - set_property(TARGET ${PROJECT_NAME} PROPERTY CUDA_ARCHITECTURES 61) -endif() - -target_include_directories(${PROJECT_NAME} PUBLIC ${PROJECT_SOURCE_DIR}/include) -target_link_libraries(${PROJECT_NAME} PUBLIC utilities) - -target_compile_features(${PROJECT_NAME} - PUBLIC cxx_std_14 - PRIVATE cxx_std_17 -) - diff --git a/IfcPlusPlus/src/external/manifold/src/collider/include/collider.h b/IfcPlusPlus/src/external/manifold/src/collider/include/collider.h deleted file mode 100644 index bc41ebb5f..000000000 --- a/IfcPlusPlus/src/external/manifold/src/collider/include/collider.h +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2021 The Manifold Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once -#include "public.h" -#include "sparse.h" -#include "vec_dh.h" - -namespace manifold { - -/** @ingroup Private */ -class Collider { - public: - Collider() {} - Collider(const VecDH& leafBB, const VecDH& leafMorton); - // Aborts and returns false if transform is not axis aligned. - bool Transform(glm::mat4x3); - void UpdateBoxes(const VecDH& leafBB); - // Collisions returns a sparse result, where i is the query index and j is - // the leaf index where their bounding boxes overlap. - template - SparseIndices Collisions(const VecDH& queriesIn) const; - - private: - VecDH nodeBBox_; - VecDH nodeParent_; - // even nodes are leaves, odd nodes are internal, root is 1 - VecDH> internalChildren_; - - int NumInternal() const { return internalChildren_.size(); }; - int NumLeaves() const { return NumInternal() + 1; }; -}; - -} // namespace manifold diff --git a/IfcPlusPlus/src/external/manifold/src/collider/src/collider.cpp b/IfcPlusPlus/src/external/manifold/src/collider/src/collider.cpp deleted file mode 100644 index 0b06512fd..000000000 --- a/IfcPlusPlus/src/external/manifold/src/collider/src/collider.cpp +++ /dev/null @@ -1,340 +0,0 @@ -// Copyright 2021 The Manifold Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "collider.h" - -#include "par.h" -#include "utils.h" - -#ifdef _MSC_VER -#include -#endif - -// Adjustable parameters -constexpr int kInitialLength = 128; -constexpr int kLengthMultiple = 4; -// Fundamental constants -constexpr int kRoot = 1; - -#ifdef _MSC_VER - -#ifndef _WINDEF_ -typedef unsigned long DWORD; -#endif - -uint32_t __inline ctz(uint32_t value) { - DWORD trailing_zero = 0; - - if (_BitScanForward(&trailing_zero, value)) { - return trailing_zero; - } else { - // This is undefined, I better choose 32 than 0 - return 32; - } -} - -uint32_t __inline clz(uint32_t value) { - DWORD leading_zero = 0; - - if (_BitScanReverse(&leading_zero, value)) { - return 31 - leading_zero; - } else { - // Same remarks as above - return 32; - } -} -#endif - -namespace { -using namespace manifold; - -__host__ __device__ bool IsLeaf(int node) { return node % 2 == 0; } -__host__ __device__ bool IsInternal(int node) { return node % 2 == 1; } -__host__ __device__ int Node2Internal(int node) { return (node - 1) / 2; } -__host__ __device__ int Internal2Node(int internal) { return internal * 2 + 1; } -__host__ __device__ int Node2Leaf(int node) { return node / 2; } -__host__ __device__ int Leaf2Node(int leaf) { return leaf * 2; } - -struct CreateRadixTree { - int* nodeParent_; - thrust::pair* internalChildren_; - const VecDc leafMorton_; - - __host__ __device__ int PrefixLength(uint32_t a, uint32_t b) const { -// count-leading-zeros is used to find the number of identical highest-order -// bits -#ifdef __CUDA_ARCH__ - return __clz(a ^ b); -#else - -#ifdef _MSC_VER - // return __lzcnt(a ^ b); - return clz(a ^ b); -#else - return __builtin_clz(a ^ b); -#endif - -#endif - } - - __host__ __device__ int PrefixLength(int i, int j) const { - if (j < 0 || j >= leafMorton_.size()) { - return -1; - } else { - int out; - if (leafMorton_[i] == leafMorton_[j]) - // use index to disambiguate - out = 32 + - PrefixLength(static_cast(i), static_cast(j)); - else - out = PrefixLength(leafMorton_[i], leafMorton_[j]); - return out; - } - } - - __host__ __device__ int RangeEnd(int i) const { - // Determine direction of range (+1 or -1) - int dir = PrefixLength(i, i + 1) - PrefixLength(i, i - 1); - dir = (dir > 0) - (dir < 0); - // Compute conservative range length with exponential increase - int commonPrefix = PrefixLength(i, i - dir); - int max_length = kInitialLength; - while (PrefixLength(i, i + dir * max_length) > commonPrefix) - max_length *= kLengthMultiple; - // Compute precise range length with binary search - int length = 0; - for (int step = max_length / 2; step > 0; step /= 2) { - if (PrefixLength(i, i + dir * (length + step)) > commonPrefix) - length += step; - } - return i + dir * length; - } - - __host__ __device__ int FindSplit(int first, int last) const { - int commonPrefix = PrefixLength(first, last); - // Find the furthest object that shares more than commonPrefix bits with the - // first one, using binary search. - int split = first; - int step = last - first; - do { - step = (step + 1) >> 1; // divide by 2, rounding up - int newSplit = split + step; - if (newSplit < last) { - int splitPrefix = PrefixLength(first, newSplit); - if (splitPrefix > commonPrefix) split = newSplit; - } - } while (step > 1); - return split; - } - - __host__ __device__ void operator()(int internal) { - int first = internal; - // Find the range of objects with a common prefix - int last = RangeEnd(first); - if (first > last) thrust::swap(first, last); - // Determine where the next-highest difference occurs - int split = FindSplit(first, last); - int child1 = split == first ? Leaf2Node(split) : Internal2Node(split); - ++split; - int child2 = split == last ? Leaf2Node(split) : Internal2Node(split); - // Record parent_child relationships. - internalChildren_[internal].first = child1; - internalChildren_[internal].second = child2; - int node = Internal2Node(internal); - nodeParent_[child1] = node; - nodeParent_[child2] = node; - } -}; - -template -struct FindCollisions { - thrust::pair queryTri_; - int* counts; - const Box* nodeBBox_; - const thrust::pair* internalChildren_; - - __host__ __device__ int RecordCollision(int node, - thrust::tuple& query) { - const T& queryObj = thrust::get<0>(query); - const int queryIdx = thrust::get<1>(query); - int& count = counts[queryIdx]; - - bool overlaps = nodeBBox_[node].DoesOverlap(queryObj); - if (overlaps && IsLeaf(node)) { - if (allocateOnly) { - count++; - } else { - int pos = count++; - queryTri_.first[pos] = queryIdx; - queryTri_.second[pos] = Node2Leaf(node); - } - } - return overlaps && IsInternal(node); // Should traverse into node - } - - __host__ __device__ void operator()(thrust::tuple query) { - // stack cannot overflow because radix tree has max depth 30 (Morton code) + - // 32 (index). - int stack[64]; - int top = -1; - // Depth-first search - int node = kRoot; - const int queryIdx = thrust::get<1>(query); - // same implies that this query do not have any collision - if (!allocateOnly && counts[queryIdx] == counts[queryIdx + 1]) return; - while (1) { - int internal = Node2Internal(node); - int child1 = internalChildren_[internal].first; - int child2 = internalChildren_[internal].second; - - int traverse1 = RecordCollision(child1, query); - int traverse2 = RecordCollision(child2, query); - - if (!traverse1 && !traverse2) { - if (top < 0) break; // done - node = stack[top--]; // get a saved node - } else { - node = traverse1 ? child1 : child2; // go here next - if (traverse1 && traverse2) { - stack[++top] = child2; // save the other for later - } - } - } - } -}; - -struct BuildInternalBoxes { - Box* nodeBBox_; - int* counter_; - const int* nodeParent_; - const thrust::pair* internalChildren_; - - __host__ __device__ void operator()(int leaf) { - int node = Leaf2Node(leaf); - do { - node = nodeParent_[node]; - int internal = Node2Internal(node); - if (AtomicAdd(counter_[internal], 1) == 0) return; - nodeBBox_[node] = nodeBBox_[internalChildren_[internal].first].Union( - nodeBBox_[internalChildren_[internal].second]); - } while (node != kRoot); - } -}; - -struct TransformBox { - const glm::mat4x3 transform; - __host__ __device__ void operator()(Box& box) { - box = box.Transform(transform); - } -}; -} // namespace - -namespace manifold { - -/** - * Creates a Bounding Volume Hierarchy (BVH) from an input set of axis-aligned - * bounding boxes and corresponding Morton codes. It is assumed these vectors - * are already sorted by increasing Morton code. - */ -Collider::Collider(const VecDH& leafBB, - const VecDH& leafMorton) { - ASSERT(leafBB.size() == leafMorton.size(), userErr, - "vectors must be the same length"); - int num_nodes = 2 * leafBB.size() - 1; - // assign and allocate members - nodeBBox_.resize(num_nodes); - nodeParent_.resize(num_nodes, -1); - internalChildren_.resize(leafBB.size() - 1, thrust::make_pair(-1, -1)); - // organize tree - for_each_n(autoPolicy(NumInternal()), countAt(0), NumInternal(), - CreateRadixTree( - {nodeParent_.ptrD(), internalChildren_.ptrD(), leafMorton})); - UpdateBoxes(leafBB); -} - -/** - * For a vector of query objects, this returns a sparse array of overlaps - * between the queries and the bounding boxes of the collider. Queries are - * normally axis-aligned bounding boxes. Points can also be used, and this case - * overlaps are defined as lying in the XY projection of the bounding box. - */ -template -SparseIndices Collider::Collisions(const VecDH& queriesIn) const { - // note that the length is 1 larger than the number of queries so the last - // element can store the sum when using exclusive scan - VecDH counts(queriesIn.size() + 1, 0); - auto policy = autoPolicy(queriesIn.size()); - // compute the number of collisions to determine the size for allocation and - // offset, this avoids the need for atomic - for_each_n(policy, zip(queriesIn.cbegin(), countAt(0)), queriesIn.size(), - FindCollisions( - {thrust::pair(nullptr, nullptr), counts.ptrD(), - nodeBBox_.ptrD(), internalChildren_.ptrD()})); - // compute start index for each query and total count - exclusive_scan(policy, counts.begin(), counts.end(), counts.begin()); - SparseIndices queryTri(counts.back()); - // actually recording collisions - for_each_n( - policy, zip(queriesIn.cbegin(), countAt(0)), queriesIn.size(), - FindCollisions({queryTri.ptrDpq(), counts.ptrD(), - nodeBBox_.ptrD(), internalChildren_.ptrD()})); - return queryTri; -} - -/** - * Recalculate the collider's internal bounding boxes without changing the - * hierarchy. - */ -void Collider::UpdateBoxes(const VecDH& leafBB) { - ASSERT(leafBB.size() == NumLeaves(), userErr, - "must have the same number of updated boxes as original"); - // copy in leaf node Boxes - strided_range::Iter> leaves(nodeBBox_.begin(), nodeBBox_.end(), 2); - auto policy = autoPolicy(NumInternal()); - copy(policy, leafBB.cbegin(), leafBB.cend(), leaves.begin()); - // create global counters - VecDH counter(NumInternal(), 0); - // kernel over leaves to save internal Boxes - for_each_n( - policy, countAt(0), NumLeaves(), - BuildInternalBoxes({nodeBBox_.ptrD(), counter.ptrD(), nodeParent_.ptrD(), - internalChildren_.ptrD()})); -} - -/** - * Apply axis-aligned transform to all bounding boxes. If transform is not - * axis-aligned, abort and return false to indicate recalculation is necessary. - */ -bool Collider::Transform(glm::mat4x3 transform) { - bool axisAligned = true; - for (int row : {0, 1, 2}) { - int count = 0; - for (int col : {0, 1, 2}) { - if (transform[col][row] == 0.0f) ++count; - } - if (count != 2) axisAligned = false; - } - if (axisAligned) { - for_each(autoPolicy(nodeBBox_.size()), nodeBBox_.begin(), nodeBBox_.end(), - TransformBox({transform})); - } - return axisAligned; -} - -template SparseIndices Collider::Collisions(const VecDH&) const; - -template SparseIndices Collider::Collisions( - const VecDH&) const; - -} // namespace manifold diff --git a/IfcPlusPlus/src/external/manifold/src/constructors.cpp b/IfcPlusPlus/src/external/manifold/src/constructors.cpp deleted file mode 100644 index 34c31d213..000000000 --- a/IfcPlusPlus/src/external/manifold/src/constructors.cpp +++ /dev/null @@ -1,421 +0,0 @@ -// Copyright 2021 The Manifold Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -#include "csg_tree.h" -#include "graph.h" -#include "impl.h" -#include "par.h" -#include "polygon.h" - -namespace { -using namespace manifold; -using namespace thrust::placeholders; - -struct ToSphere { - float length; - __host__ __device__ void operator()(glm::vec3& v) { - v = glm::cos(glm::half_pi() * (1.0f - v)); - v = length * glm::normalize(v); - if (isnan(v.x)) v = glm::vec3(0.0); - } -}; - -struct Equals { - int val; - __host__ __device__ bool operator()(int x) { return x == val; } -}; - -struct RemoveFace { - const Halfedge* halfedge; - const int* vertLabel; - const int keepLabel; - - __host__ __device__ bool operator()(int face) { - return vertLabel[halfedge[3 * face].startVert] != keepLabel; - } -}; -} // namespace - -namespace manifold { -/** - * Constructs a smooth version of the input mesh by creating tangents; this - * method will throw if you have supplied tangents with your mesh already. The - * actual triangle resolution is unchanged; use the Refine() method to - * interpolate to a higher-resolution curve. - * - * By default, every edge is calculated for maximum smoothness (very much - * approximately), attempting to minimize the maximum mean Curvature magnitude. - * No higher-order derivatives are considered, as the interpolation is - * independent per triangle, only sharing constraints on their boundaries. - * - * @param mesh input Mesh. - * @param sharpenedEdges If desired, you can supply a vector of sharpened - * halfedges, which should in general be a small subset of all halfedges. Order - * of entries doesn't matter, as each one specifies the desired smoothness - * (between zero and one, with one the default for all unspecified halfedges) - * and the halfedge index (3 * triangle index + [0,1,2] where 0 is the edge - * between triVert 0 and 1, etc). - * - * At a smoothness value of zero, a sharp crease is made. The smoothness is - * interpolated along each edge, so the specified value should be thought of as - * an average. Where exactly two sharpened edges meet at a vertex, their - * tangents are rotated to be colinear so that the sharpened edge can be - * continuous. Vertices with only one sharpened edge are completely smooth, - * allowing sharpened edges to smoothly vanish at termination. A single vertex - * can be sharpened by sharping all edges that are incident on it, allowing - * cones to be formed. - */ -Manifold Manifold::Smooth(const Mesh& mesh, - const std::vector& sharpenedEdges) { - ASSERT(mesh.halfedgeTangent.empty(), std::runtime_error, - "when supplying tangents, the normal constructor should be used " - "rather than Smooth()."); - - std::shared_ptr impl = std::make_shared(mesh); - impl->CreateTangents(sharpenedEdges); - return Manifold(impl); -} - -/** - * Constructs a tetrahedron centered at the origin with one vertex at (1,1,1) - * and the rest at similarly symmetric points. - */ -Manifold Manifold::Tetrahedron() { - return Manifold(std::make_shared(Impl::Shape::TETRAHEDRON)); -} - -/** - * Constructs a unit cube (edge lengths all one), by default in the first - * octant, touching the origin. - * - * @param size The X, Y, and Z dimensions of the box. - * @param center Set to true to shift the center to the origin. - */ -Manifold Manifold::Cube(glm::vec3 size, bool center) { - auto cube = Manifold(std::make_shared(Impl::Shape::CUBE)); - cube = cube.Scale(size); - if (center) cube = cube.Translate(-size / 2.0f); - return cube; -} - -/** - * A convenience constructor for the common case of extruding a circle. Can also - * form cones if both radii are specified. - * - * @param height Z-extent - * @param radiusLow Radius of bottom circle. Must be positive. - * @param radiusHigh Radius of top circle. Can equal zero. Default is equal to - * radiusLow. - * @param circularSegments How many line segments to use around the circle. - * Default is calculated by the static Defaults. - * @param center Set to true to shift the center to the origin. Default is - * origin at the bottom. - */ -Manifold Manifold::Cylinder(float height, float radiusLow, float radiusHigh, - int circularSegments, bool center) { - float scale = radiusHigh >= 0.0f ? radiusHigh / radiusLow : 1.0f; - float radius = fmax(radiusLow, radiusHigh); - int n = circularSegments > 2 ? circularSegments : GetCircularSegments(radius); - Polygons circle(1); - float dPhi = 360.0f / n; - for (int i = 0; i < n; ++i) { - circle[0].push_back( - {radiusLow * glm::vec2(cosd(dPhi * i), sind(dPhi * i)), 0}); - } - Manifold cylinder = - Manifold::Extrude(circle, height, 0, 0.0f, glm::vec2(scale)); - if (center) - cylinder = cylinder.Translate(glm::vec3(0.0f, 0.0f, -height / 2.0f)); - return cylinder; -} - -/** - * Constructs a geodesic sphere of a given radius. - * - * @param radius Radius of the sphere. Must be positive. - * @param circularSegments Number of segments along its - * diameter. This number will always be rounded up to the nearest factor of - * four, as this sphere is constructed by refining an octahedron. This means - * there are a circle of vertices on all three of the axis planes. Default is - * calculated by the static Defaults. - */ -Manifold Manifold::Sphere(float radius, int circularSegments) { - int n = circularSegments > 0 ? (circularSegments + 3) / 4 - : GetCircularSegments(radius) / 4; - auto pImpl_ = std::make_shared(Impl::Shape::OCTAHEDRON); - pImpl_->Subdivide(n); - for_each_n(autoPolicy(pImpl_->NumVert()), pImpl_->vertPos_.begin(), - pImpl_->NumVert(), ToSphere({radius})); - pImpl_->Finish(); - // Ignore preceding octahedron. - pImpl_->ReinitializeReference(Impl::meshIDCounter_.fetch_add(1)); - return Manifold(pImpl_); -} - -/** - * Constructs a manifold from a set of polygons by extruding them along the - * Z-axis. - * - * @param crossSection A set of non-overlapping polygons to extrude. - * @param height Z-extent of extrusion. - * @param nDivisions Number of extra copies of the crossSection to insert into - * the shape vertically; especially useful in combination with twistDegrees to - * avoid interpolation artifacts. Default is none. - * @param twistDegrees Amount to twist the top crossSection relative to the - * bottom, interpolated linearly for the divisions in between. - * @param scaleTop Amount to scale the top (independently in X and Y). If the - * scale is {0, 0}, a pure cone is formed with only a single vertex at the top. - * Default {1, 1}. - */ -Manifold Manifold::Extrude(Polygons crossSection, float height, int nDivisions, - float twistDegrees, glm::vec2 scaleTop) { - scaleTop.x = glm::max(scaleTop.x, 0.0f); - scaleTop.y = glm::max(scaleTop.y, 0.0f); - - auto pImpl_ = std::make_shared(); - ++nDivisions; - auto& vertPos = pImpl_->vertPos_; - VecDH triVertsDH; - auto& triVerts = triVertsDH; - int nCrossSection = 0; - bool isCone = scaleTop.x == 0.0 && scaleTop.y == 0.0; - int idx = 0; - for (auto& poly : crossSection) { - nCrossSection += poly.size(); - for (PolyVert& polyVert : poly) { - vertPos.push_back({polyVert.pos.x, polyVert.pos.y, 0.0f}); - polyVert.idx = idx++; - } - } - for (int i = 1; i < nDivisions + 1; ++i) { - float alpha = i / float(nDivisions); - float phi = alpha * twistDegrees; - glm::mat2 transform(cosd(phi), sind(phi), -sind(phi), cosd(phi)); - glm::vec2 scale = glm::mix(glm::vec2(1.0f), scaleTop, alpha); - transform = transform * glm::mat2(scale.x, 0.0f, 0.0f, scale.y); - int j = 0; - int idx = 0; - for (const auto& poly : crossSection) { - for (int vert = 0; vert < poly.size(); ++vert) { - int offset = idx + nCrossSection * i; - int thisVert = vert + offset; - int lastVert = (vert == 0 ? poly.size() : vert) - 1 + offset; - if (i == nDivisions && isCone) { - triVerts.push_back({nCrossSection * i + j, lastVert - nCrossSection, - thisVert - nCrossSection}); - } else { - glm::vec2 pos = transform * poly[vert].pos; - vertPos.push_back({pos.x, pos.y, height * alpha}); - triVerts.push_back({thisVert, lastVert, thisVert - nCrossSection}); - triVerts.push_back( - {lastVert, lastVert - nCrossSection, thisVert - nCrossSection}); - } - } - ++j; - idx += poly.size(); - } - } - if (isCone) - for (int j = 0; j < crossSection.size(); ++j) // Duplicate vertex for Genus - vertPos.push_back({0.0f, 0.0f, height}); - std::vector top = Triangulate(crossSection); - for (const glm::ivec3& tri : top) { - triVerts.push_back({tri[0], tri[2], tri[1]}); - if (!isCone) triVerts.push_back(tri + nCrossSection * nDivisions); - } - - pImpl_->CreateHalfedges(triVertsDH); - pImpl_->Finish(); - pImpl_->InitializeNewReference(); - return Manifold(pImpl_); -} - -/** - * Constructs a manifold from a set of polygons by revolving this cross-section - * around its Y-axis and then setting this as the Z-axis of the resulting - * manifold. If the polygons cross the Y-axis, only the part on the positive X - * side is used. Geometrically valid input will result in geometrically valid - * output. - * - * @param crossSection A set of non-overlapping polygons to revolve. - * @param circularSegments Number of segments along its diameter. Default is - * calculated by the static Defaults. - */ -Manifold Manifold::Revolve(const Polygons& crossSection, int circularSegments) { - float radius = 0.0f; - for (const auto& poly : crossSection) { - for (const auto& vert : poly) { - radius = fmax(radius, vert.pos.x); - } - } - int nDivisions = - circularSegments > 2 ? circularSegments : GetCircularSegments(radius); - auto pImpl_ = std::make_shared(); - auto& vertPos = pImpl_->vertPos_; - VecDH triVertsDH; - auto& triVerts = triVertsDH; - float dPhi = 360.0f / nDivisions; - for (const auto& poly : crossSection) { - int start = -1; - for (int polyVert = 0; polyVert < poly.size(); ++polyVert) { - if (poly[polyVert].pos.x <= 0) { - start = polyVert; - break; - } - } - if (start == -1) { // poly all positive - for (int polyVert = 0; polyVert < poly.size(); ++polyVert) { - int startVert = vertPos.size(); - int lastStart = - startVert + - (polyVert == 0 ? nDivisions * (poly.size() - 1) : -nDivisions); - for (int slice = 0; slice < nDivisions; ++slice) { - int lastSlice = (slice == 0 ? nDivisions : slice) - 1; - float phi = slice * dPhi; - glm::vec2 pos = poly[polyVert].pos; - vertPos.push_back({pos.x * cosd(phi), pos.x * sind(phi), pos.y}); - triVerts.push_back({startVert + slice, startVert + lastSlice, - lastStart + lastSlice}); - triVerts.push_back( - {lastStart + lastSlice, lastStart + slice, startVert + slice}); - } - } - } else { // poly crosses zero - int polyVert = start; - glm::vec2 pos = poly[polyVert].pos; - do { - glm::vec2 lastPos = pos; - polyVert = (polyVert + 1) % poly.size(); - pos = poly[polyVert].pos; - if (pos.x > 0) { - if (lastPos.x <= 0) { - float a = pos.x / (pos.x - lastPos.x); - vertPos.push_back({0.0f, 0.0f, glm::mix(pos.y, lastPos.y, a)}); - } - int startVert = vertPos.size(); - for (int slice = 0; slice < nDivisions; ++slice) { - int lastSlice = (slice == 0 ? nDivisions : slice) - 1; - float phi = slice * dPhi; - glm::vec2 pos = poly[polyVert].pos; - vertPos.push_back({pos.x * cosd(phi), pos.x * sind(phi), pos.y}); - if (lastPos.x > 0) { - triVerts.push_back({startVert + slice, startVert + lastSlice, - startVert - nDivisions + lastSlice}); - triVerts.push_back({startVert - nDivisions + lastSlice, - startVert - nDivisions + slice, - startVert + slice}); - } else { - triVerts.push_back( - {startVert - 1, startVert + slice, startVert + lastSlice}); - } - } - } else if (lastPos.x > 0) { - int startVert = vertPos.size(); - float a = pos.x / (pos.x - lastPos.x); - vertPos.push_back({0.0f, 0.0f, glm::mix(pos.y, lastPos.y, a)}); - for (int slice = 0; slice < nDivisions; ++slice) { - int lastSlice = (slice == 0 ? nDivisions : slice) - 1; - triVerts.push_back({startVert, startVert - nDivisions + lastSlice, - startVert - nDivisions + slice}); - } - } - } while (polyVert != start); - } - } - - pImpl_->CreateHalfedges(triVertsDH); - pImpl_->Finish(); - pImpl_->InitializeNewReference(); - return Manifold(pImpl_); -} - -/** - * Constructs a new manifold from a vector of other manifolds. This is a purely - * topological operation, so care should be taken to avoid creating - * overlapping results. It is the inverse operation of Decompose(). - * - * @param manifolds A vector of Manifolds to lazy-union together. - */ -Manifold Manifold::Compose(const std::vector& manifolds) { - std::vector> children; - for (const auto& manifold : manifolds) { - children.push_back(manifold.pNode_->ToLeafNode()); - } - return Manifold(std::make_shared(CsgLeafNode::Compose(children))); -} - -/** - * This operation returns a vector of Manifolds that are topologically - * disconnected. If everything is connected, the vector is length one, - * containing a copy of the original. It is the inverse operation of Compose(). - */ -std::vector Manifold::Decompose() const { - Graph graph; - auto pImpl_ = GetCsgLeafNode().GetImpl(); - for (int i = 0; i < NumVert(); ++i) { - graph.add_nodes(i); - } - for (const Halfedge& halfedge : pImpl_->halfedge_) { - if (halfedge.IsForward()) - graph.add_edge(halfedge.startVert, halfedge.endVert); - } - std::vector components; - const int numLabel = ConnectedComponents(components, graph); - - if (numLabel == 1) { - std::vector meshes(1); - meshes[0] = *this; - return meshes; - } - VecDH vertLabel(components); - - std::vector meshes; - for (int i = 0; i < numLabel; ++i) { - auto impl = std::make_shared(); - // inherit original object's precision - impl->precision_ = pImpl_->precision_; - impl->vertPos_.resize(NumVert()); - VecDH vertNew2Old(NumVert()); - auto policy = autoPolicy(NumVert()); - auto start = zip(impl->vertPos_.begin(), vertNew2Old.begin()); - int nVert = - copy_if( - policy, zip(pImpl_->vertPos_.begin(), countAt(0)), - zip(pImpl_->vertPos_.end(), countAt(NumVert())), vertLabel.begin(), - zip(impl->vertPos_.begin(), vertNew2Old.begin()), Equals({i})) - - start; - impl->vertPos_.resize(nVert); - - VecDH faceNew2Old(NumTri()); - sequence(policy, faceNew2Old.begin(), faceNew2Old.end()); - - int nFace = - remove_if( - policy, faceNew2Old.begin(), faceNew2Old.end(), - RemoveFace({pImpl_->halfedge_.cptrD(), vertLabel.cptrD(), i})) - - faceNew2Old.begin(); - faceNew2Old.resize(nFace); - - impl->GatherFaces(*pImpl_, faceNew2Old); - impl->ReindexVerts(vertNew2Old, pImpl_->NumVert()); - - impl->Finish(); - - meshes.push_back(Manifold(impl)); - } - return meshes; -} -} // namespace manifold diff --git a/IfcPlusPlus/src/external/manifold/src/csg_tree.cpp b/IfcPlusPlus/src/external/manifold/src/csg_tree.cpp deleted file mode 100644 index 181f57307..000000000 --- a/IfcPlusPlus/src/external/manifold/src/csg_tree.cpp +++ /dev/null @@ -1,464 +0,0 @@ -// Copyright 2022 The Manifold Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "csg_tree.h" - -#include - -#include "boolean3.h" -#include "impl.h" -#include "par.h" - -namespace { -using namespace manifold; -struct Transform4x3 { - const glm::mat4x3 transform; - - __host__ __device__ glm::vec3 operator()(glm::vec3 position) { - return transform * glm::vec4(position, 1.0f); - } -}; - -struct TransformNormals { - const glm::mat3 transform; - - __host__ __device__ glm::vec3 operator()(glm::vec3 normal) { - normal = glm::normalize(transform * normal); - if (isnan(normal.x)) normal = glm::vec3(0.0f); - return normal; - } -}; - -struct UpdateTriBary { - const int nextBary; - - __host__ __device__ BaryRef operator()(BaryRef ref) { - for (int i : {0, 1, 2}) - if (ref.vertBary[i] >= 0) ref.vertBary[i] += nextBary; - return ref; - } -}; - -struct UpdateHalfedge { - const int nextVert; - const int nextEdge; - const int nextFace; - - __host__ __device__ Halfedge operator()(Halfedge edge) { - edge.startVert += nextVert; - edge.endVert += nextVert; - edge.pairedHalfedge += nextEdge; - edge.face += nextFace; - return edge; - } -}; - -struct CheckOverlap { - const Box *boxes; - const size_t i; - __host__ __device__ bool operator()(int j) { - return boxes[i].DoesOverlap(boxes[j]); - } -}; -} // namespace -namespace manifold { - -std::shared_ptr CsgNode::Translate(const glm::vec3 &t) const { - glm::mat4x3 transform(1.0f); - transform[3] += t; - return Transform(transform); -} - -std::shared_ptr CsgNode::Scale(const glm::vec3 &v) const { - glm::mat4x3 transform(1.0f); - for (int i : {0, 1, 2}) transform[i] *= v; - return Transform(transform); -} - -std::shared_ptr CsgNode::Rotate(float xDegrees, float yDegrees, - float zDegrees) const { - glm::mat3 rX(1.0f, 0.0f, 0.0f, // - 0.0f, cosd(xDegrees), sind(xDegrees), // - 0.0f, -sind(xDegrees), cosd(xDegrees)); - glm::mat3 rY(cosd(yDegrees), 0.0f, -sind(yDegrees), // - 0.0f, 1.0f, 0.0f, // - sind(yDegrees), 0.0f, cosd(yDegrees)); - glm::mat3 rZ(cosd(zDegrees), sind(zDegrees), 0.0f, // - -sind(zDegrees), cosd(zDegrees), 0.0f, // - 0.0f, 0.0f, 1.0f); - glm::mat4x3 transform(rZ * rY * rX); - return Transform(transform); -} - -CsgLeafNode::CsgLeafNode() : pImpl_(std::make_shared()) {} - -CsgLeafNode::CsgLeafNode(std::shared_ptr pImpl_) - : pImpl_(pImpl_) {} - -CsgLeafNode::CsgLeafNode(std::shared_ptr pImpl_, - glm::mat4x3 transform_) - : pImpl_(pImpl_), transform_(transform_) {} - -std::shared_ptr CsgLeafNode::GetImpl() const { - if (transform_ == glm::mat4x3(1.0f)) return pImpl_; - pImpl_ = - std::make_shared(pImpl_->Transform(transform_)); - transform_ = glm::mat4x3(1.0f); - return pImpl_; -} - -glm::mat4x3 CsgLeafNode::GetTransform() const { return transform_; } - -std::shared_ptr CsgLeafNode::ToLeafNode() const { - return std::make_shared(*this); -} - -std::shared_ptr CsgLeafNode::Transform(const glm::mat4x3 &m) const { - return std::make_shared(pImpl_, m * glm::mat4(transform_)); -} - -CsgNodeType CsgLeafNode::GetNodeType() const { return CsgNodeType::LEAF; } - -/** - * Efficient union of a set of pairwise disjoint meshes. - */ -Manifold::Impl CsgLeafNode::Compose( - const std::vector> &nodes) { - float precision = -1; - int numVert = 0; - int numEdge = 0; - int numTri = 0; - int numBary = 0; - int meshids = 0; - for (auto &node : nodes) { - meshids += node->pImpl_->meshids; - float nodeOldScale = node->pImpl_->bBox_.Scale(); - float nodeNewScale = - node->pImpl_->bBox_.Transform(node->transform_).Scale(); - float nodePrecision = node->pImpl_->precision_; - nodePrecision *= glm::max(1.0f, nodeNewScale / nodeOldScale); - nodePrecision = glm::max(nodePrecision, kTolerance * nodeNewScale); - if (!glm::isfinite(nodePrecision)) nodePrecision = -1; - precision = glm::max(precision, nodePrecision); - - numVert += node->pImpl_->NumVert(); - numEdge += node->pImpl_->NumEdge(); - numTri += node->pImpl_->NumTri(); - numBary += node->pImpl_->meshRelation_.barycentric.size(); - } - - Manifold::Impl combined; - combined.meshids = meshids; - combined.precision_ = precision; - combined.vertPos_.resize(numVert); - combined.halfedge_.resize(2 * numEdge); - combined.faceNormal_.resize(numTri); - combined.halfedgeTangent_.resize(2 * numEdge); - combined.meshRelation_.barycentric.resize(numBary); - combined.meshRelation_.triBary.resize(numTri); - auto policy = autoPolicy(numTri); - - int nextVert = 0; - int nextEdge = 0; - int nextTri = 0; - int nextBary = 0; - for (auto &node : nodes) { - if (node->transform_ == glm::mat4x3(1.0f)) { - copy(policy, node->pImpl_->vertPos_.begin(), node->pImpl_->vertPos_.end(), - combined.vertPos_.begin() + nextVert); - copy(policy, node->pImpl_->faceNormal_.begin(), - node->pImpl_->faceNormal_.end(), - combined.faceNormal_.begin() + nextTri); - } else { - // no need to apply the transform to the node, just copy the vertices and - // face normals and apply transform on the fly - auto vertPosBegin = thrust::make_transform_iterator( - node->pImpl_->vertPos_.begin(), Transform4x3({node->transform_})); - glm::mat3 normalTransform = - glm::inverse(glm::transpose(glm::mat3(node->transform_))); - auto faceNormalBegin = - thrust::make_transform_iterator(node->pImpl_->faceNormal_.begin(), - TransformNormals({normalTransform})); - copy_n(policy, vertPosBegin, node->pImpl_->vertPos_.size(), - combined.vertPos_.begin() + nextVert); - copy_n(policy, faceNormalBegin, node->pImpl_->faceNormal_.size(), - combined.faceNormal_.begin() + nextTri); - } - copy(policy, node->pImpl_->halfedgeTangent_.begin(), - node->pImpl_->halfedgeTangent_.end(), - combined.halfedgeTangent_.begin() + nextEdge); - copy(policy, node->pImpl_->meshRelation_.barycentric.begin(), - node->pImpl_->meshRelation_.barycentric.end(), - combined.meshRelation_.barycentric.begin() + nextBary); - transform(policy, node->pImpl_->meshRelation_.triBary.begin(), - node->pImpl_->meshRelation_.triBary.end(), - combined.meshRelation_.triBary.begin() + nextTri, - UpdateTriBary({nextBary})); - transform(policy, node->pImpl_->halfedge_.begin(), - node->pImpl_->halfedge_.end(), - combined.halfedge_.begin() + nextEdge, - UpdateHalfedge({nextVert, nextEdge, nextTri})); - - // Since the nodes may be copies containing the same meshIDs, it is - // important to increment them separately so that each node instance gets - // unique meshIDs. - combined.IncrementMeshIDs(nextTri, node->pImpl_->NumTri()); - - nextVert += node->pImpl_->NumVert(); - nextEdge += 2 * node->pImpl_->NumEdge(); - nextTri += node->pImpl_->NumTri(); - nextBary += node->pImpl_->meshRelation_.barycentric.size(); - } - // required to remove parts that are smaller than the precision - combined.SimplifyTopology(); - combined.Finish(); - return combined; -} - -CsgOpNode::CsgOpNode() {} - -CsgOpNode::CsgOpNode(const std::vector> &children, - Manifold::OpType op) - : impl_(std::make_shared()) { - impl_->children_ = children; - SetOp(op); - // opportunistically flatten the tree without costly evaluation - GetChildren(false); -} - -CsgOpNode::CsgOpNode(std::vector> &&children, - Manifold::OpType op) - : impl_(std::make_shared()) { - impl_->children_ = children; - SetOp(op); - // opportunistically flatten the tree without costly evaluation - GetChildren(false); -} - -std::shared_ptr CsgOpNode::Transform(const glm::mat4x3 &m) const { - auto node = std::make_shared(); - node->impl_ = impl_; - node->transform_ = m * glm::mat4(transform_); - return node; -} - -std::shared_ptr CsgOpNode::ToLeafNode() const { - if (cache_ != nullptr) return cache_; - if (impl_->children_.empty()) return nullptr; - // turn the children into leaf nodes - GetChildren(); - auto &children_ = impl_->children_; - if (children_.size() > 1) { - switch (impl_->op_) { - case CsgNodeType::UNION: - BatchUnion(); - break; - case CsgNodeType::INTERSECTION: { - std::vector> impls; - for (auto &child : children_) { - impls.push_back( - std::dynamic_pointer_cast(child)->GetImpl()); - } - BatchBoolean(Manifold::OpType::INTERSECT, impls); - children_.clear(); - children_.push_back(std::make_shared(impls.front())); - break; - }; - case CsgNodeType::DIFFERENCE: { - // take the lhs out and treat the remaining nodes as the rhs, perform - // union optimization for them - auto lhs = std::dynamic_pointer_cast(children_.front()); - children_.erase(children_.begin()); - BatchUnion(); - auto rhs = std::dynamic_pointer_cast(children_.front()); - children_.clear(); - Boolean3 boolean(*lhs->GetImpl(), *rhs->GetImpl(), - Manifold::OpType::SUBTRACT); - children_.push_back( - std::make_shared(std::make_shared( - boolean.Result(Manifold::OpType::SUBTRACT)))); - }; - case CsgNodeType::LEAF: - // unreachable - break; - } - } - // children_ must contain only one CsgLeafNode now, and its Transform will - // give CsgLeafNode as well - cache_ = std::dynamic_pointer_cast( - children_.front()->Transform(transform_)); - return cache_; -} - -/** - * Efficient boolean operation on a set of nodes utilizing commutativity of the - * operation. Only supports union and intersection. - */ -void CsgOpNode::BatchBoolean( - Manifold::OpType operation, - std::vector> &results) { - ASSERT(operation != Manifold::OpType::SUBTRACT, logicErr, - "BatchBoolean doesn't support Difference."); - auto cmpFn = [](std::shared_ptr a, - std::shared_ptr b) { - // invert the order because we want a min heap - return a->NumVert() > b->NumVert(); - }; - - // apply boolean operations starting from smaller meshes - // the assumption is that boolean operations on smaller meshes is faster, - // due to less data being copied and processed - std::make_heap(results.begin(), results.end(), cmpFn); - while (results.size() > 1) { - std::pop_heap(results.begin(), results.end(), cmpFn); - auto a = std::move(results.back()); - results.pop_back(); - std::pop_heap(results.begin(), results.end(), cmpFn); - auto b = std::move(results.back()); - results.pop_back(); - // boolean operation - Boolean3 boolean(*a, *b, operation); - results.push_back( - std::make_shared(boolean.Result(operation))); - std::push_heap(results.begin(), results.end(), cmpFn); - } -} - -/** - * Efficient union operation on a set of nodes by doing Compose as much as - * possible. - * Note: Due to some unknown issues with `Compose`, we are now doing - * `BatchBoolean` instead of using `Compose` for non-intersecting manifolds. - */ -void CsgOpNode::BatchUnion() const { - // INVARIANT: children_ is a vector of leaf nodes - // this kMaxUnionSize is a heuristic to avoid the pairwise disjoint check - // with O(n^2) complexity to take too long. - // If the number of children exceeded this limit, we will operate on chunks - // with size kMaxUnionSize. - constexpr int kMaxUnionSize = 1000; - auto &children_ = impl_->children_; - while (children_.size() > 1) { - const int start = (children_.size() > kMaxUnionSize) - ? (children_.size() - kMaxUnionSize) - : 0; - VecDH boxes; - boxes.reserve(children_.size() - start); - for (int i = start; i < children_.size(); i++) { - boxes.push_back(std::dynamic_pointer_cast(children_[i]) - ->GetImpl() - ->bBox_); - } - const Box *boxesD = boxes.cptrD(); - // partition the children into a set of disjoint sets - // each set contains a set of children that are pairwise disjoint - std::vector> disjointSets; - for (size_t i = 0; i < boxes.size(); i++) { - auto lambda = [boxesD, i](const VecDH &set) { - return find_if( - autoPolicy(set.size()), set.begin(), set.end(), - CheckOverlap({boxesD, i})) == set.end(); - }; - auto it = std::find_if(disjointSets.begin(), disjointSets.end(), lambda); - if (it == disjointSets.end()) { - disjointSets.push_back(std::vector{i}); - } else { - it->push_back(i); - } - } - // compose each set of disjoint children - std::vector> impls; - for (const auto &set : disjointSets) { - if (set.size() == 1) { - impls.push_back( - std::dynamic_pointer_cast(children_[start + set[0]]) - ->GetImpl()); - } else { - std::vector> tmp; - for (size_t j : set) { - tmp.push_back( - std::dynamic_pointer_cast(children_[start + j])); - } - impls.push_back( - std::make_shared(CsgLeafNode::Compose(tmp))); - } - } - BatchBoolean(Manifold::OpType::ADD, impls); - children_.erase(children_.begin() + start, children_.end()); - children_.push_back(std::make_shared(impls.back())); - // move it to the front as we process from the back, and the newly added - // child should be quite complicated - std::swap(children_.front(), children_.back()); - } -} - -/** - * Flatten the children to a list of leaf nodes and return them. - * If finalize is true, the list will be guaranteed to be a list of leaf nodes - * (i.e. no ops). Otherwise, the list may contain ops. - * Note that this function will not apply the transform to children, as they may - * be shared with other nodes. - */ -std::vector> &CsgOpNode::GetChildren( - bool finalize) const { - auto &children_ = impl_->children_; - if (children_.empty() || (impl_->simplified_ && !finalize) || - impl_->flattened_) - return children_; - impl_->simplified_ = true; - impl_->flattened_ = finalize; - std::vector> newChildren; - - CsgNodeType op = impl_->op_; - for (auto &child : children_) { - if (child->GetNodeType() == op && child.use_count() == 1 && - std::dynamic_pointer_cast(child)->impl_.use_count() == 1) { - auto grandchildren = - std::dynamic_pointer_cast(child)->GetChildren(finalize); - int start = children_.size(); - for (auto &grandchild : grandchildren) { - newChildren.push_back(grandchild->Transform(child->GetTransform())); - } - } else { - if (!finalize || child->GetNodeType() == CsgNodeType::LEAF) { - newChildren.push_back(child); - } else { - newChildren.push_back(child->ToLeafNode()); - } - } - // special handling for difference: we treat it as first - (second + third + - // ...) so op = UNION after the first node - if (op == CsgNodeType::DIFFERENCE) op = CsgNodeType::UNION; - } - children_ = newChildren; - return children_; -} - -void CsgOpNode::SetOp(Manifold::OpType op) { - switch (op) { - case Manifold::OpType::ADD: - impl_->op_ = CsgNodeType::UNION; - break; - case Manifold::OpType::SUBTRACT: - impl_->op_ = CsgNodeType::DIFFERENCE; - break; - case Manifold::OpType::INTERSECT: - impl_->op_ = CsgNodeType::INTERSECTION; - break; - } -} - -glm::mat4x3 CsgOpNode::GetTransform() const { return transform_; } - -} // namespace manifold diff --git a/IfcPlusPlus/src/external/manifold/src/csg_tree.h b/IfcPlusPlus/src/external/manifold/src/csg_tree.h deleted file mode 100644 index d9cabccbf..000000000 --- a/IfcPlusPlus/src/external/manifold/src/csg_tree.h +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright 2022 The Manifold Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once -#include "manifold.h" - -namespace manifold { - -enum class CsgNodeType { UNION, INTERSECTION, DIFFERENCE, LEAF }; - -class CsgLeafNode; - -class CsgNode { - public: - virtual std::shared_ptr ToLeafNode() const = 0; - virtual std::shared_ptr Transform(const glm::mat4x3 &m) const = 0; - virtual CsgNodeType GetNodeType() const = 0; - virtual glm::mat4x3 GetTransform() const = 0; - - std::shared_ptr Translate(const glm::vec3 &t) const; - std::shared_ptr Scale(const glm::vec3 &s) const; - std::shared_ptr Rotate(float xDegrees = 0, float yDegrees = 0, - float zDegrees = 0) const; -}; - -class CsgLeafNode final : public CsgNode { - public: - CsgLeafNode(); - CsgLeafNode(std::shared_ptr pImpl_); - CsgLeafNode(std::shared_ptr pImpl_, - glm::mat4x3 transform_); - - std::shared_ptr GetImpl() const; - - std::shared_ptr ToLeafNode() const override; - - std::shared_ptr Transform(const glm::mat4x3 &m) const override; - - CsgNodeType GetNodeType() const override; - - glm::mat4x3 GetTransform() const override; - - static Manifold::Impl Compose( - const std::vector> &nodes); - - private: - mutable std::shared_ptr pImpl_; - mutable glm::mat4x3 transform_ = glm::mat4x3(1.0f); -}; - -class CsgOpNode final : public CsgNode { - public: - CsgOpNode(); - - CsgOpNode(const std::vector> &children, - Manifold::OpType op); - - CsgOpNode(std::vector> &&children, - Manifold::OpType op); - - std::shared_ptr Transform(const glm::mat4x3 &m) const override; - - std::shared_ptr ToLeafNode() const override; - - CsgNodeType GetNodeType() const override { return impl_->op_; } - - glm::mat4x3 GetTransform() const override; - - private: - struct Impl { - CsgNodeType op_; - mutable std::vector> children_; - mutable bool simplified_ = false; - mutable bool flattened_ = false; - }; - std::shared_ptr impl_ = nullptr; - glm::mat4x3 transform_ = glm::mat4x3(1.0f); - // the following fields are for lazy evaluation, so they are mutable - mutable std::shared_ptr cache_ = nullptr; - - void SetOp(Manifold::OpType); - - static void BatchBoolean( - Manifold::OpType operation, - std::vector> &results); - - void BatchUnion() const; - - std::vector> &GetChildren( - bool finalize = true) const; -}; - -} // namespace manifold diff --git a/IfcPlusPlus/src/external/manifold/src/edge_op.cpp b/IfcPlusPlus/src/external/manifold/src/edge_op.cpp deleted file mode 100644 index 234ec0d75..000000000 --- a/IfcPlusPlus/src/external/manifold/src/edge_op.cpp +++ /dev/null @@ -1,504 +0,0 @@ -// Copyright 2021 The Manifold Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "impl.h" -#include "par.h" - -namespace { -using namespace manifold; - -__host__ __device__ glm::ivec3 TriOf(int edge) { - glm::ivec3 triEdge; - triEdge[0] = edge; - triEdge[1] = NextHalfedge(triEdge[0]); - triEdge[2] = NextHalfedge(triEdge[1]); - return triEdge; -} - -__host__ __device__ bool Is01Longest(glm::vec2 v0, glm::vec2 v1, glm::vec2 v2) { - const glm::vec2 e[3] = {v1 - v0, v2 - v1, v0 - v2}; - float l[3]; - for (int i : {0, 1, 2}) l[i] = glm::dot(e[i], e[i]); - return l[0] > l[1] && l[0] > l[2]; -} - -struct DuplicateEdge { - const Halfedge* sortedHalfedge; - - __host__ __device__ bool operator()(int edge) { - const Halfedge& halfedge = sortedHalfedge[edge]; - const Halfedge& nextHalfedge = sortedHalfedge[edge + 1]; - return halfedge.startVert == nextHalfedge.startVert && - halfedge.endVert == nextHalfedge.endVert; - } -}; - -struct ShortEdge { - const Halfedge* halfedge; - const glm::vec3* vertPos; - const float precision; - - __host__ __device__ bool operator()(int edge) { - if (halfedge[edge].pairedHalfedge < 0) return false; - // Flag short edges - const glm::vec3 delta = - vertPos[halfedge[edge].endVert] - vertPos[halfedge[edge].startVert]; - return glm::dot(delta, delta) < precision * precision; - } -}; - -struct FlagEdge { - const Halfedge* halfedge; - const BaryRef* triBary; - - __host__ __device__ bool operator()(int edge) { - if (halfedge[edge].pairedHalfedge < 0) return false; - // Flag redundant edges - those where the startVert is surrounded by only - // two original triangles. - const BaryRef ref0 = triBary[edge / 3]; - int current = NextHalfedge(halfedge[edge].pairedHalfedge); - const BaryRef ref1 = triBary[current / 3]; - while (current != edge) { - current = NextHalfedge(halfedge[current].pairedHalfedge); - int tri = current / 3; - const BaryRef ref = triBary[tri]; - if ((ref.meshID != ref0.meshID || ref.tri != ref0.tri) && - (ref.meshID != ref1.meshID || ref.tri != ref1.tri)) - return false; - } - return true; - } -}; - -struct SwappableEdge { - const Halfedge* halfedge; - const glm::vec3* vertPos; - const glm::vec3* triNormal; - const float precision; - - __host__ __device__ bool operator()(int edge) { - if (halfedge[edge].pairedHalfedge < 0) return false; - - int tri = halfedge[edge].face; - glm::ivec3 triedge = TriOf(edge); - glm::mat3x2 projection = GetAxisAlignedProjection(triNormal[tri]); - glm::vec2 v[3]; - for (int i : {0, 1, 2}) - v[i] = projection * vertPos[halfedge[triedge[i]].startVert]; - if (CCW(v[0], v[1], v[2], precision) > 0 || !Is01Longest(v[0], v[1], v[2])) - return false; - - // Switch to neighbor's projection. - edge = halfedge[edge].pairedHalfedge; - tri = halfedge[edge].face; - triedge = TriOf(edge); - projection = GetAxisAlignedProjection(triNormal[tri]); - for (int i : {0, 1, 2}) - v[i] = projection * vertPos[halfedge[triedge[i]].startVert]; - return CCW(v[0], v[1], v[2], precision) > 0 || - Is01Longest(v[0], v[1], v[2]); - } -}; -} // namespace - -namespace manifold { - -/** - * Collapses degenerate triangles by removing edges shorter than precision_ and - * any edge that is preceeded by an edge that joins the same two face relations. - * It also performs edge swaps on the long edges of degenerate triangles, though - * there are some configurations of degenerates that cannot be removed this way. - * - * Before collapsing edges, the mesh is checked for duplicate edges (more than - * one pair of triangles sharing the same edge), which are removed by - * duplicating one vert and adding two triangles. These degenerate triangles are - * likely to be collapsed again in the subsequent simplification. - * - * Note when an edge collapse would result in something non-manifold, the - * vertices are duplicated in such a way as to remove handles or separate - * meshes, thus decreasing the Genus(). It only increases when meshes that have - * collapsed to just a pair of triangles are removed entirely. - * - * Rather than actually removing the edges, this step merely marks them for - * removal, by setting vertPos to NaN and halfedge to {-1, -1, -1, -1}. - */ -void Manifold::Impl::SimplifyTopology() { - if (!halfedge_.size()) return; - - auto policy = autoPolicy(halfedge_.size()); - - VecDH halfedge(halfedge_); - VecDH idx(halfedge_.size()); - sequence(policy, idx.begin(), idx.end()); - sort_by_key(policy, halfedge.begin(), halfedge.end(), idx.begin()); - - VecDH flaggedEdges(halfedge_.size()); - - int numFlagged = - copy_if( - policy, idx.begin(), idx.end() - 1, countAt(0), flaggedEdges.begin(), - DuplicateEdge({halfedge.cptrD()})) - - flaggedEdges.begin(); - flaggedEdges.resize(numFlagged); - - for (const int edge : flaggedEdges) DedupeEdge(edge); - - flaggedEdges.resize(halfedge_.size()); - numFlagged = - copy_if( - policy, countAt(0), countAt(halfedge_.size()), flaggedEdges.begin(), - ShortEdge({halfedge_.cptrD(), vertPos_.cptrD(), precision_})) - - flaggedEdges.begin(); - flaggedEdges.resize(numFlagged); - - for (const int edge : flaggedEdges) CollapseEdge(edge); - - flaggedEdges.resize(halfedge_.size()); - numFlagged = - copy_if( - policy, countAt(0), countAt(halfedge_.size()), flaggedEdges.begin(), - FlagEdge({halfedge_.cptrD(), meshRelation_.triBary.cptrD()})) - - flaggedEdges.begin(); - flaggedEdges.resize(numFlagged); - - for (const int edge : flaggedEdges) CollapseEdge(edge); - - flaggedEdges.resize(halfedge_.size()); - numFlagged = - copy_if( - policy, countAt(0), countAt(halfedge_.size()), flaggedEdges.begin(), - SwappableEdge({halfedge_.cptrD(), vertPos_.cptrD(), - faceNormal_.cptrD(), precision_})) - - flaggedEdges.begin(); - flaggedEdges.resize(numFlagged); - - for (const int edge : flaggedEdges) { - RecursiveEdgeSwap(edge); - } -} - -void Manifold::Impl::DedupeEdge(const int edge) { - // Orbit endVert - const int startVert = halfedge_[edge].startVert; - const int endVert = halfedge_[edge].endVert; - int current = halfedge_[NextHalfedge(edge)].pairedHalfedge; - while (current != edge) { - const int vert = halfedge_[current].startVert; - if (vert == startVert) { - const int newVert = vertPos_.size(); - vertPos_.push_back(vertPos_[endVert]); - if (vertNormal_.size() > 0) vertNormal_.push_back(vertNormal_[endVert]); - current = halfedge_[NextHalfedge(current)].pairedHalfedge; - const int opposite = halfedge_[NextHalfedge(edge)].pairedHalfedge; - - UpdateVert(newVert, current, opposite); - - int newHalfedge = halfedge_.size(); - int newFace = newHalfedge / 3; - int oldFace = halfedge_[current].face; - int outsideVert = halfedge_[current].startVert; - halfedge_.push_back({endVert, newVert, -1, newFace}); - halfedge_.push_back({newVert, outsideVert, -1, newFace}); - halfedge_.push_back({outsideVert, endVert, -1, newFace}); - PairUp(newHalfedge + 2, halfedge_[current].pairedHalfedge); - PairUp(newHalfedge + 1, current); - if (meshRelation_.triBary.size() > 0) - meshRelation_.triBary.push_back(meshRelation_.triBary[oldFace]); - if (faceNormal_.size() > 0) faceNormal_.push_back(faceNormal_[oldFace]); - - newHalfedge += 3; - ++newFace; - oldFace = halfedge_[opposite].face; - outsideVert = halfedge_[opposite].startVert; - halfedge_.push_back({newVert, endVert, -1, newFace}); - halfedge_.push_back({endVert, outsideVert, -1, newFace}); - halfedge_.push_back({outsideVert, newVert, -1, newFace}); - PairUp(newHalfedge + 2, halfedge_[opposite].pairedHalfedge); - PairUp(newHalfedge + 1, opposite); - PairUp(newHalfedge, newHalfedge - 3); - if (meshRelation_.triBary.size() > 0) - meshRelation_.triBary.push_back(meshRelation_.triBary[oldFace]); - if (faceNormal_.size() > 0) faceNormal_.push_back(faceNormal_[oldFace]); - - break; - } - - current = halfedge_[NextHalfedge(current)].pairedHalfedge; - } -} - -void Manifold::Impl::PairUp(int edge0, int edge1) { - halfedge_[edge0].pairedHalfedge = edge1; - halfedge_[edge1].pairedHalfedge = edge0; -} - -// Traverses CW around startEdge.endVert from startEdge to endEdge -// (edgeEdge.endVert must == startEdge.endVert), updating each edge to point -// to vert instead. -void Manifold::Impl::UpdateVert(int vert, int startEdge, int endEdge) { - size_t ii = 0; - while (startEdge != endEdge) { - halfedge_[startEdge].endVert = vert; - startEdge = NextHalfedge(startEdge); - halfedge_[startEdge].startVert = vert; - startEdge = halfedge_[startEdge].pairedHalfedge; - - if( ii > 1000 ) // fg: emergency exit. TODO: check loop before calling UpdateVert - { - std::logic_error ex("UpdateVert failed"); - throw std::exception(ex); - } - ++ii; - } -} - -// In the event that the edge collapse would create a non-manifold edge, -// instead we duplicate the two verts and attach the manifolds the other way -// across this edge. -void Manifold::Impl::FormLoop(int current, int end) { - int startVert = vertPos_.size(); - vertPos_.push_back(vertPos_[halfedge_[current].startVert]); - int endVert = vertPos_.size(); - vertPos_.push_back(vertPos_[halfedge_[current].endVert]); - - int oldMatch = halfedge_[current].pairedHalfedge; - int newMatch = halfedge_[end].pairedHalfedge; - - UpdateVert(startVert, oldMatch, newMatch); - UpdateVert(endVert, end, current); - - halfedge_[current].pairedHalfedge = newMatch; - halfedge_[newMatch].pairedHalfedge = current; - halfedge_[end].pairedHalfedge = oldMatch; - halfedge_[oldMatch].pairedHalfedge = end; - - RemoveIfFolded(end); -} - -void Manifold::Impl::CollapseTri(const glm::ivec3& triEdge) { - int pair1 = halfedge_[triEdge[1]].pairedHalfedge; - int pair2 = halfedge_[triEdge[2]].pairedHalfedge; - halfedge_[pair1].pairedHalfedge = pair2; - halfedge_[pair2].pairedHalfedge = pair1; - for (int i : {0, 1, 2}) { - halfedge_[triEdge[i]] = {-1, -1, -1, -1}; - } -} - -void Manifold::Impl::RemoveIfFolded(int edge) { - const glm::ivec3 tri0edge = TriOf(edge); - const glm::ivec3 tri1edge = TriOf(halfedge_[edge].pairedHalfedge); - if (halfedge_[tri0edge[1]].endVert == halfedge_[tri1edge[1]].endVert) { - for (int i : {0, 1, 2}) { - vertPos_[halfedge_[tri0edge[i]].startVert] = glm::vec3(NAN); - halfedge_[tri0edge[i]] = {-1, -1, -1, -1}; - halfedge_[tri1edge[i]] = {-1, -1, -1, -1}; - } - } -} - -void Manifold::Impl::CollapseEdge(const int edge) { - VecDH& triBary = meshRelation_.triBary; - - const Halfedge toRemove = halfedge_[edge]; - if (toRemove.pairedHalfedge < 0) return; - - const int endVert = toRemove.endVert; - const glm::ivec3 tri0edge = TriOf(edge); - const glm::ivec3 tri1edge = TriOf(toRemove.pairedHalfedge); - - const glm::vec3 pNew = vertPos_[endVert]; - const glm::vec3 pOld = vertPos_[toRemove.startVert]; - const glm::vec3 delta = pNew - pOld; - const bool shortEdge = glm::dot(delta, delta) < precision_ * precision_; - - std::vector edges; - // Orbit endVert - int current = halfedge_[tri0edge[1]].pairedHalfedge; - size_t ii = 0; - while (current != tri1edge[2]) { - current = NextHalfedge(current); - edges.push_back(current); - current = halfedge_[current].pairedHalfedge; - if( ii > 10000 ) - { - throw std::exception(); - } - ++ii; - } - - // Orbit startVert - int start = halfedge_[tri1edge[1]].pairedHalfedge; - const BaryRef ref0 = triBary[edge / 3]; - const BaryRef ref1 = triBary[toRemove.pairedHalfedge / 3]; - if (!shortEdge) { - current = start; - glm::vec3 pLast = vertPos_[halfedge_[tri1edge[1]].endVert]; - while (current != tri0edge[2]) { - current = NextHalfedge(current); - glm::vec3 pNext = vertPos_[halfedge_[current].endVert]; - const int tri = current / 3; - const BaryRef ref = triBary[tri]; - // Don't collapse if the edge is not redundant (this may have changed due - // to the collapse of neighbors). - if ((ref.meshID != ref0.meshID || ref.tri != ref0.tri) && - (ref.meshID != ref1.meshID || ref.tri != ref1.tri)) - return; - - // Don't collapse edge if it would cause a triangle to invert. - const glm::mat3x2 projection = GetAxisAlignedProjection(faceNormal_[tri]); - if (CCW(projection * pNext, projection * pLast, projection * pNew, - precision_) < 0) - return; - - pLast = pNext; - current = halfedge_[current].pairedHalfedge; - } - } - - // Remove toRemove.startVert and replace with endVert. - vertPos_[toRemove.startVert] = glm::vec3(NAN); - CollapseTri(tri1edge); - - // Orbit startVert - current = start; - while (current != tri0edge[2]) { - current = NextHalfedge(current); - - if (!shortEdge) { - // Update the shifted triangles to the vertBary of endVert - const int tri = current / 3; - const int vIdx = current - 3 * tri; - triBary[tri].vertBary[vIdx] = - (ref0.meshID == triBary[tri].meshID && ref0.tri == triBary[tri].tri) - ? ref0.vertBary[(edge + 1) % 3] - : ref1.vertBary[toRemove.pairedHalfedge % 3]; - } - - const int vert = halfedge_[current].endVert; - const int next = halfedge_[current].pairedHalfedge; - for (int i = 0; i < edges.size(); ++i) { - if (vert == halfedge_[edges[i]].endVert) { - FormLoop(edges[i], current); - start = next; - edges.resize(i); - break; - } - } - current = next; - } - - UpdateVert(endVert, start, tri0edge[2]); - CollapseTri(tri0edge); - RemoveIfFolded(start); -} - -void Manifold::Impl::RecursiveEdgeSwap(const int edge) { - VecDH& triBary = meshRelation_.triBary; - - if (edge < 0) return; - const int pair = halfedge_[edge].pairedHalfedge; - if (pair < 0) return; - - const glm::ivec3 tri0edge = TriOf(edge); - const glm::ivec3 tri1edge = TriOf(pair); - const glm::ivec3 perm0 = TriOf(edge % 3); - const glm::ivec3 perm1 = TriOf(pair % 3); - - glm::mat3x2 projection = GetAxisAlignedProjection(faceNormal_[edge / 3]); - glm::vec2 v[4]; - for (int i : {0, 1, 2}) - v[i] = projection * vertPos_[halfedge_[tri0edge[i]].startVert]; - // Only operate on the long edge of a degenerate triangle. - if (CCW(v[0], v[1], v[2], precision_) > 0 || !Is01Longest(v[0], v[1], v[2])) - return; - - // Switch to neighbor's projection. - projection = GetAxisAlignedProjection(faceNormal_[halfedge_[pair].face]); - for (int i : {0, 1, 2}) - v[i] = projection * vertPos_[halfedge_[tri0edge[i]].startVert]; - v[3] = projection * vertPos_[halfedge_[tri1edge[2]].startVert]; - - auto SwapEdge = [&]() { - // The 0-verts are swapped to the opposite 2-verts. - const int v0 = halfedge_[tri0edge[2]].startVert; - const int v1 = halfedge_[tri1edge[2]].startVert; - halfedge_[tri0edge[0]].startVert = v1; - halfedge_[tri0edge[2]].endVert = v1; - halfedge_[tri1edge[0]].startVert = v0; - halfedge_[tri1edge[2]].endVert = v0; - PairUp(tri0edge[0], halfedge_[tri1edge[2]].pairedHalfedge); - PairUp(tri1edge[0], halfedge_[tri0edge[2]].pairedHalfedge); - PairUp(tri0edge[2], tri1edge[2]); - // Both triangles are now subsets of the neighboring triangle. - const int tri0 = halfedge_[tri0edge[0]].face; - const int tri1 = halfedge_[tri1edge[0]].face; - faceNormal_[tri0] = faceNormal_[tri1]; - triBary[tri0] = triBary[tri1]; - triBary[tri0].vertBary[perm0[1]] = triBary[tri1].vertBary[perm1[0]]; - triBary[tri0].vertBary[perm0[0]] = triBary[tri1].vertBary[perm1[2]]; - // Calculate a new barycentric coordinate for the split triangle. - const glm::vec3 uvw0 = UVW(triBary[tri1].vertBary[perm1[0]], - meshRelation_.barycentric.cptrH()); - const glm::vec3 uvw1 = UVW(triBary[tri1].vertBary[perm1[1]], - meshRelation_.barycentric.cptrH()); - const float l01 = glm::length(v[1] - v[0]); - const float l02 = glm::length(v[2] - v[0]); - const float a = glm::max(0.0f, glm::min(1.0f, l02 / l01)); - const glm::vec3 uvw2 = a * uvw0 + (1 - a) * uvw1; - // And assign it. - const int newBary = meshRelation_.barycentric.size(); - meshRelation_.barycentric.push_back(uvw2); - triBary[tri1].vertBary[perm1[0]] = newBary; - triBary[tri0].vertBary[perm0[2]] = newBary; - - // if the new edge already exists, duplicate the verts and split the mesh. - int current = halfedge_[tri1edge[0]].pairedHalfedge; - const int endVert = halfedge_[tri1edge[1]].endVert; - while (current != tri0edge[1]) { - current = NextHalfedge(current); - if (halfedge_[current].endVert == endVert) { - FormLoop(tri0edge[2], current); - RemoveIfFolded(tri0edge[2]); - return; - } - current = halfedge_[current].pairedHalfedge; - } - }; - - // Only operate if the other triangles are not degenerate. - if (CCW(v[1], v[0], v[3], precision_) <= 0) { - if (!Is01Longest(v[1], v[0], v[3])) return; - // Two facing, long-edge degenerates can swap. - SwapEdge(); - const glm::vec2 e23 = v[3] - v[2]; - if (glm::dot(e23, e23) < precision_ * precision_) { - CollapseEdge(tri0edge[2]); - } else { - RecursiveEdgeSwap(tri0edge[0]); - RecursiveEdgeSwap(tri0edge[1]); - RecursiveEdgeSwap(tri1edge[0]); - RecursiveEdgeSwap(tri1edge[1]); - } - return; - } else if (CCW(v[0], v[3], v[2], precision_) <= 0 || - CCW(v[1], v[2], v[3], precision_) <= 0) { - return; - } - // Normal path - SwapEdge(); - RecursiveEdgeSwap(halfedge_[tri0edge[1]].pairedHalfedge); - RecursiveEdgeSwap(halfedge_[tri1edge[0]].pairedHalfedge); -} -} // namespace manifold diff --git a/IfcPlusPlus/src/external/manifold/src/face_op.cpp b/IfcPlusPlus/src/external/manifold/src/face_op.cpp deleted file mode 100644 index 2494d9047..000000000 --- a/IfcPlusPlus/src/external/manifold/src/face_op.cpp +++ /dev/null @@ -1,195 +0,0 @@ -// Copyright 2021 The Manifold Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -#include "impl.h" -#include "polygon.h" - -namespace manifold { - -/** - * Triangulates the faces. In this case, the halfedge_ vector is not yet a set - * of triangles as required by this data structure, but is instead a set of - * general faces with the input faceEdge vector having length of the number of - * faces + 1. The values are indicies into the halfedge_ vector for the first - * edge of each face, with the final value being the length of the halfedge_ - * vector itself. Upon return, halfedge_ has been lengthened and properly - * represents the mesh as a set of triangles as usual. In this process the - * faceNormal_ values are retained, repeated as necessary. - */ -void Manifold::Impl::Face2Tri(const VecDH& faceEdge, - const VecDH& faceRef, - const VecDH& halfedgeBary) { - VecDH triVerts; - VecDH triNormal; - VecDH& triBary = meshRelation_.triBary; - triBary.resize(0); - triVerts.reserve(halfedge_.size()); - triNormal.reserve(halfedge_.size()); - triBary.reserve(halfedge_.size()); - - for (int face = 0; face < faceEdge.size() - 1; ++face) { - const int firstEdge = faceEdge[face]; - const int lastEdge = faceEdge[face + 1]; - const int numEdge = lastEdge - firstEdge; - ASSERT(numEdge >= 3, topologyErr, "face has less than three edges."); - const glm::vec3 normal = faceNormal_[face]; - - auto linearSearch = [](const int* mapping, int value) { - int i = 0; - while (mapping[i] != value) ++i; - return i; - }; - - if (numEdge == 3) { // Single triangle - int mapping[3] = {halfedge_[firstEdge].startVert, - halfedge_[firstEdge + 1].startVert, - halfedge_[firstEdge + 2].startVert}; - glm::ivec3 tri(halfedge_[firstEdge].startVert, - halfedge_[firstEdge + 1].startVert, - halfedge_[firstEdge + 2].startVert); - glm::ivec3 ends(halfedge_[firstEdge].endVert, - halfedge_[firstEdge + 1].endVert, - halfedge_[firstEdge + 2].endVert); - if (ends[0] == tri[2]) { - std::swap(tri[1], tri[2]); - std::swap(ends[1], ends[2]); - } - ASSERT(ends[0] == tri[1] && ends[1] == tri[2] && ends[2] == tri[0], - topologyErr, "These 3 edges do not form a triangle!"); - - triVerts.push_back(tri); - triNormal.push_back(normal); - triBary.push_back(faceRef[face]); - for (int k : {0, 1, 2}) { - int index = linearSearch(mapping, tri[k]); - triBary.back().vertBary[k] = halfedgeBary[firstEdge + index]; - } - } else if (numEdge == 4) { // Pair of triangles - int mapping[4] = {halfedge_[firstEdge].startVert, - halfedge_[firstEdge + 1].startVert, - halfedge_[firstEdge + 2].startVert, - halfedge_[firstEdge + 3].startVert}; - const glm::mat3x2 projection = GetAxisAlignedProjection(normal); - auto triCCW = [&projection, this](const glm::ivec3 tri) { - return CCW(projection * this->vertPos_[tri[0]], - projection * this->vertPos_[tri[1]], - projection * this->vertPos_[tri[2]], precision_) >= 0; - }; - - glm::ivec3 tri0(halfedge_[firstEdge].startVert, - halfedge_[firstEdge].endVert, -1); - glm::ivec3 tri1(-1, -1, tri0[0]); - for (const int i : {1, 2, 3}) { - if (halfedge_[firstEdge + i].startVert == tri0[1]) { - tri0[2] = halfedge_[firstEdge + i].endVert; - tri1[0] = tri0[2]; - } - if (halfedge_[firstEdge + i].endVert == tri0[0]) { - tri1[1] = halfedge_[firstEdge + i].startVert; - } - } - ASSERT(glm::all(glm::greaterThanEqual(tri0, glm::ivec3(0))) && - glm::all(glm::greaterThanEqual(tri1, glm::ivec3(0))), - topologyErr, "non-manifold quad!"); - bool firstValid = triCCW(tri0) && triCCW(tri1); - tri0[2] = tri1[1]; - tri1[2] = tri0[1]; - bool secondValid = triCCW(tri0) && triCCW(tri1); - - if (!secondValid) { - tri0[2] = tri1[0]; - tri1[2] = tri0[0]; - } else if (firstValid) { - glm::vec3 firstCross = vertPos_[tri0[0]] - vertPos_[tri1[0]]; - glm::vec3 secondCross = vertPos_[tri0[1]] - vertPos_[tri1[1]]; - if (glm::dot(firstCross, firstCross) < - glm::dot(secondCross, secondCross)) { - tri0[2] = tri1[0]; - tri1[2] = tri0[0]; - } - } - - for (auto tri : {tri0, tri1}) { - triVerts.push_back(tri); - triNormal.push_back(normal); - triBary.push_back(faceRef[face]); - for (int k : {0, 1, 2}) { - int index = linearSearch(mapping, tri[k]); - triBary.back().vertBary[k] = halfedgeBary[firstEdge + index]; - } - } - } else { // General triangulation - const glm::mat3x2 projection = GetAxisAlignedProjection(normal); - - std::map vertBary; - for (int j = firstEdge; j < lastEdge; ++j) - vertBary[halfedge_[j].startVert] = halfedgeBary[j]; - - const Polygons polys = Face2Polygons(face, projection, faceEdge); - - std::vector newTris = Triangulate(polys, precision_); - - for (auto tri : newTris) { - triVerts.push_back(tri); - triNormal.push_back(normal); - triBary.push_back(faceRef[face]); - for (int k : {0, 1, 2}) { - triBary.back().vertBary[k] = vertBary[tri[k]]; - } - } - } - } - faceNormal_ = std::move(triNormal); - CreateHalfedges(triVerts); -} - -/** - * For the input face index, return a set of 2D polygons formed by the input - * projection of the vertices. - */ -Polygons Manifold::Impl::Face2Polygons(int face, glm::mat3x2 projection, - const VecDH& faceEdge) const { - const int firstEdge = faceEdge[face]; - const int lastEdge = faceEdge[face + 1]; - - std::map vert_edge; - for (int edge = firstEdge; edge < lastEdge; ++edge) { - const bool inserted = - vert_edge.emplace(std::make_pair(halfedge_[edge].startVert, edge)) - .second; - ASSERT(inserted, topologyErr, "face has duplicate vertices."); - } - - Polygons polys; - int startEdge = 0; - int thisEdge = startEdge; - while (1) { - if (thisEdge == startEdge) { - if (vert_edge.empty()) break; - startEdge = vert_edge.begin()->second; - thisEdge = startEdge; - polys.push_back({}); - } - int vert = halfedge_[thisEdge].startVert; - polys.back().push_back({projection * vertPos_[vert], vert}); - const auto result = vert_edge.find(halfedge_[thisEdge].endVert); - ASSERT(result != vert_edge.end(), topologyErr, "non-manifold edge"); - thisEdge = result->second; - vert_edge.erase(result); - } - return polys; -} -} // namespace manifold diff --git a/IfcPlusPlus/src/external/manifold/src/impl.cpp b/IfcPlusPlus/src/external/manifold/src/impl.cpp deleted file mode 100644 index 55134ed1f..000000000 --- a/IfcPlusPlus/src/external/manifold/src/impl.cpp +++ /dev/null @@ -1,711 +0,0 @@ -// Copyright 2021 The Manifold Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "impl.h" - -#include - -#include -#include -#include - -#include "graph.h" -#include "hashtable.h" -#include "par.h" - -namespace { -using namespace manifold; - -__host__ __device__ void AtomicAddVec3(glm::vec3& target, - const glm::vec3& add) { - for (int i : {0, 1, 2}) { -#ifdef __CUDA_ARCH__ - atomicAdd(&target[i], add[i]); -#else - std::atomic& tar = reinterpret_cast&>(target[i]); - float old_val = tar.load(std::memory_order_relaxed); - while (!tar.compare_exchange_weak(old_val, old_val + add[i], - std::memory_order_relaxed)) - ; -#endif - } -} - -struct Normalize { - __host__ __device__ void operator()(glm::vec3& v) { v = SafeNormalize(v); } -}; - -struct Transform4x3 { - const glm::mat4x3 transform; - - __host__ __device__ glm::vec3 operator()(glm::vec3 position) { - return transform * glm::vec4(position, 1.0f); - } -}; - -struct TransformNormals { - const glm::mat3 transform; - - __host__ __device__ glm::vec3 operator()(glm::vec3 normal) { - normal = glm::normalize(transform * normal); - if (isnan(normal.x)) normal = glm::vec3(0.0f); - return normal; - } -}; - -struct AssignNormals { - glm::vec3* vertNormal; - const glm::vec3* vertPos; - const Halfedge* halfedges; - const float precision; - const bool calculateTriNormal; - - __host__ __device__ void operator()(thrust::tuple in) { - glm::vec3& triNormal = thrust::get<0>(in); - const int face = thrust::get<1>(in); - - glm::ivec3 triVerts; - for (int i : {0, 1, 2}) triVerts[i] = halfedges[3 * face + i].startVert; - - glm::vec3 edge[3]; - for (int i : {0, 1, 2}) { - const int j = (i + 1) % 3; - edge[i] = glm::normalize(vertPos[triVerts[j]] - vertPos[triVerts[i]]); - } - - if (calculateTriNormal) { - triNormal = glm::normalize(glm::cross(edge[0], edge[1])); - if (isnan(triNormal.x)) triNormal = glm::vec3(0, 0, 1); - } - - // corner angles - glm::vec3 phi; - float dot = -glm::dot(edge[2], edge[0]); - phi[0] = dot >= 1 ? 0 : (dot <= -1 ? glm::pi() : glm::acos(dot)); - dot = -glm::dot(edge[0], edge[1]); - phi[1] = dot >= 1 ? 0 : (dot <= -1 ? glm::pi() : glm::acos(dot)); - phi[2] = glm::pi() - phi[0] - phi[1]; - - // assign weighted sum - for (int i : {0, 1, 2}) { - AtomicAddVec3(vertNormal[triVerts[i]], phi[i] * triNormal); - } - } -}; - -struct Tri2Halfedges { - Halfedge* halfedges; - glm::uint64_t* edges; - - __host__ __device__ void operator()( - thrust::tuple in) { - const int tri = thrust::get<0>(in); - const glm::ivec3& triVerts = thrust::get<1>(in); - for (const int i : {0, 1, 2}) { - const int j = (i + 1) % 3; - const int edge = 3 * tri + i; - halfedges[edge] = {triVerts[i], triVerts[j], -1, tri}; - // Sort the forward halfedges in front of the backward ones by setting the - // highest-order bit. - edges[edge] = glm::uint64_t(triVerts[i] < triVerts[j] ? 1 : 0) << 63 | - ((glm::uint64_t)glm::min(triVerts[i], triVerts[j])) << 32 | - glm::max(triVerts[i], triVerts[j]); - } - } -}; - -struct LinkHalfedges { - Halfedge* halfedges; - const int* ids; - const int numEdge; - - __host__ __device__ void operator()(int i) { - const int pair0 = ids[i]; - const int pair1 = ids[i + numEdge]; - halfedges[pair0].pairedHalfedge = pair1; - halfedges[pair1].pairedHalfedge = pair0; - } -}; - -struct MarkVerts { - int* vert; - - __host__ __device__ void operator()(glm::ivec3 triVerts) { - for (int i : {0, 1, 2}) { - vert[triVerts[i]] = 1; - } - } -}; - -struct ReindexTriVerts { - const int* old2new; - - __host__ __device__ void operator()(glm::ivec3& triVerts) { - for (int i : {0, 1, 2}) { - triVerts[i] = old2new[triVerts[i]]; - } - } -}; - -struct InitializeBaryRef { - const int meshID; - const Halfedge* halfedge; - - __host__ __device__ void operator()(thrust::tuple inOut) { - BaryRef& baryRef = thrust::get<0>(inOut); - int tri = thrust::get<1>(inOut); - - baryRef.meshID = meshID; - baryRef.originalID = meshID; - baryRef.tri = tri; - baryRef.vertBary = {-3, -2, -1}; - } -}; - -struct MarkMeshID { - HashTableD table; - - __host__ __device__ void operator()(BaryRef& ref) { - if (table.Full()) return; - table.Insert(ref.meshID, 1); - } -}; - -struct UpdateMeshID { - const HashTableD meshIDold2new; - const int meshIDoffset; - - __host__ __device__ void operator()(BaryRef& ref) { - ref.meshID = meshIDold2new[ref.meshID] + meshIDoffset; - } -}; - -struct CheckProperties { - const int numSets; - - __host__ __device__ bool operator()(glm::ivec3 triProp) { - bool good = true; - for (int i : {0, 1, 2}) good &= (triProp[i] >= 0 && triProp[i] < numSets); - return good; - } -}; - -struct CoplanarEdge { - float* triArea; - const Halfedge* halfedge; - const glm::vec3* vertPos; - const glm::ivec3* triProp; - const float* prop; - const float* propTol; - const int numProp; - const float precision; - - __host__ __device__ void operator()( - thrust::tuple&, int> inOut) { - thrust::pair& face2face = thrust::get<0>(inOut); - const int edgeIdx = thrust::get<1>(inOut); - - const Halfedge edge = halfedge[edgeIdx]; - if (!edge.IsForward()) return; - const Halfedge pair = halfedge[edge.pairedHalfedge]; - const glm::vec3 base = vertPos[edge.startVert]; - - const int baseNum = edgeIdx - 3 * edge.face; - const int jointNum = edge.pairedHalfedge - 3 * pair.face; - const int edgeNum = baseNum == 0 ? 2 : baseNum - 1; - const int pairNum = jointNum == 0 ? 2 : jointNum - 1; - - const glm::vec3 jointVec = vertPos[pair.startVert] - base; - const glm::vec3 edgeVec = - vertPos[halfedge[3 * edge.face + edgeNum].startVert] - base; - const glm::vec3 pairVec = - vertPos[halfedge[3 * pair.face + pairNum].startVert] - base; - - const float length = glm::max(glm::length(jointVec), glm::length(edgeVec)); - const float lengthPair = - glm::max(glm::length(jointVec), glm::length(pairVec)); - glm::vec3 normal = glm::cross(jointVec, edgeVec); - const float area = glm::length(normal); - const float areaPair = glm::length(glm::cross(pairVec, jointVec)); - // Don't link degenerate triangles - if (area < length * precision || areaPair < lengthPair * precision) return; - - const float volume = glm::abs(glm::dot(normal, pairVec)); - // Only operate on coplanar triangles - if (volume > glm::max(area, areaPair) * precision) return; - - // Check property linearity - if (area > 0) { - normal /= area; - for (int i = 0; i < numProp; ++i) { - const float scale = precision / propTol[i]; - - const float baseProp = prop[numProp * triProp[edge.face][baseNum] + i]; - const float jointProp = - prop[numProp * triProp[pair.face][jointNum] + i]; - const float edgeProp = prop[numProp * triProp[edge.face][edgeNum] + i]; - const float pairProp = prop[numProp * triProp[pair.face][pairNum] + i]; - - const glm::vec3 iJointVec = - jointVec + normal * scale * (jointProp - baseProp); - const glm::vec3 iEdgeVec = - edgeVec + normal * scale * (edgeProp - baseProp); - const glm::vec3 iPairVec = - pairVec + normal * scale * (pairProp - baseProp); - - glm::vec3 cross = glm::cross(iJointVec, iEdgeVec); - const float area = glm::max( - glm::length(cross), glm::length(glm::cross(iPairVec, iJointVec))); - const float volume = glm::abs(glm::dot(cross, iPairVec)); - // Only operate on consistent triangles - if (volume > area * precision) return; - } - } - - triArea[edge.face] = area; - triArea[pair.face] = areaPair; - face2face.first = edge.face; - face2face.second = pair.face; - } -}; - -struct EdgeBox { - const glm::vec3* vertPos; - - __host__ __device__ void operator()( - thrust::tuple inout) { - const TmpEdge& edge = thrust::get<1>(inout); - thrust::get<0>(inout) = Box(vertPos[edge.first], vertPos[edge.second]); - } -}; - -} // namespace - -namespace manifold { - -std::atomic Manifold::Impl::meshIDCounter_(1); - -/** - * Create a manifold from an input triangle Mesh. Will return an empty Manifold - * and set an Error Status if the Mesh is not manifold or otherwise invalid. - * TODO: update halfedgeTangent during SimplifyTopology. - */ -Manifold::Impl::Impl(const Mesh& mesh, - const std::vector& triProperties, - const std::vector& properties, - const std::vector& propertyTolerance) - : vertPos_(mesh.vertPos), - halfedgeTangent_(mesh.halfedgeTangent), - meshids(1) { - VecDH triVerts = mesh.triVerts; - if (!IsIndexInBounds(triVerts)) { - MarkFailure(Error::VERTEX_INDEX_OUT_OF_BOUNDS); - return; - } - RemoveUnreferencedVerts(triVerts); - - CalculateBBox(); - if (!IsFinite()) { - MarkFailure(Error::NON_FINITE_VERTEX); - return; - } - SetPrecision(); - - CreateHalfedges(triVerts); - if (!IsManifold()) { - MarkFailure(Error::NOT_MANIFOLD); - return; - } - CalculateNormals(); - InitializeNewReference(triProperties, properties, propertyTolerance); - if (status_ != Error::MANIFOLD_NO_ERROR) return; - - SimplifyTopology(); - Finish(); -} - -/** - * Create either a unit tetrahedron, cube or octahedron. The cube is in the - * first octant, while the others are symmetric about the origin. - */ -Manifold::Impl::Impl(Shape shape) : meshids(1) { - std::vector vertPos; - std::vector triVerts; - switch (shape) { - case Shape::TETRAHEDRON: - vertPos = {{-1.0f, -1.0f, 1.0f}, - {-1.0f, 1.0f, -1.0f}, - {1.0f, -1.0f, -1.0f}, - {1.0f, 1.0f, 1.0f}}; - triVerts = {{2, 0, 1}, {0, 3, 1}, {2, 3, 0}, {3, 2, 1}}; - break; - case Shape::CUBE: - vertPos = {{0.0f, 0.0f, 0.0f}, // - {1.0f, 0.0f, 0.0f}, // - {1.0f, 1.0f, 0.0f}, // - {0.0f, 1.0f, 0.0f}, // - {0.0f, 0.0f, 1.0f}, // - {1.0f, 0.0f, 1.0f}, // - {1.0f, 1.0f, 1.0f}, // - {0.0f, 1.0f, 1.0f}}; - triVerts = {{0, 2, 1}, {0, 3, 2}, // - {4, 5, 6}, {4, 6, 7}, // - {0, 1, 5}, {0, 5, 4}, // - {1, 2, 6}, {1, 6, 5}, // - {2, 3, 7}, {2, 7, 6}, // - {3, 0, 4}, {3, 4, 7}}; - break; - case Shape::OCTAHEDRON: - vertPos = {{1.0f, 0.0f, 0.0f}, // - {-1.0f, 0.0f, 0.0f}, // - {0.0f, 1.0f, 0.0f}, // - {0.0f, -1.0f, 0.0f}, // - {0.0f, 0.0f, 1.0f}, // - {0.0f, 0.0f, -1.0f}}; - triVerts = {{0, 2, 4}, {1, 5, 3}, // - {2, 1, 4}, {3, 5, 0}, // - {1, 3, 4}, {0, 5, 2}, // - {3, 0, 4}, {2, 5, 1}}; - break; - } - vertPos_ = vertPos; - CreateHalfedges(triVerts); - Finish(); - InitializeNewReference(); -} - -void Manifold::Impl::RemoveUnreferencedVerts(VecDH& triVerts) { - VecDH vertOld2New(NumVert() + 1, 0); - auto policy = autoPolicy(NumVert()); - for_each(policy, triVerts.cbegin(), triVerts.cend(), - MarkVerts({vertOld2New.ptrD() + 1})); - - const VecDH oldVertPos = vertPos_; - vertPos_.resize(copy_if( - policy, oldVertPos.cbegin(), oldVertPos.cend(), - vertOld2New.cbegin() + 1, vertPos_.begin(), - thrust::identity()) - - vertPos_.begin()); - - inclusive_scan(policy, vertOld2New.begin() + 1, vertOld2New.end(), - vertOld2New.begin() + 1); - - for_each(policy, triVerts.begin(), triVerts.end(), - ReindexTriVerts({vertOld2New.cptrD()})); -} - -void Manifold::Impl::ReinitializeReference(int meshID) { - // instead of storing the meshID, we store 0 and set the mapping to - // 0 -> meshID, because the meshID after boolean operation also starts from 0. - for_each_n(autoPolicy(NumTri()), - zip(meshRelation_.triBary.begin(), countAt(0)), NumTri(), - InitializeBaryRef({meshID, halfedge_.cptrD()})); - meshRelation_.originalID = meshID; - meshids = 1; -} - -int Manifold::Impl::InitializeNewReference( - const std::vector& triProperties, - const std::vector& properties, - const std::vector& propertyTolerance) { - meshRelation_.triBary.resize(NumTri()); - const int nextMeshID = meshIDCounter_.fetch_add(1, std::memory_order_relaxed); - ReinitializeReference(nextMeshID); - - const int numProps = propertyTolerance.size(); - - VecDH triPropertiesD(triProperties); - VecDH propertiesD(properties); - VecDH propertyToleranceD(propertyTolerance); - - if (numProps > 0) { - if (triProperties.size() != NumTri() && triProperties.size() != 0) { - MarkFailure(Error::TRI_PROPERTIES_WRONG_LENGTH); - return nextMeshID; - }; - if (properties.size() % numProps != 0) { - MarkFailure(Error::PROPERTIES_WRONG_LENGTH); - return nextMeshID; - }; - - const int numSets = properties.size() / numProps; - if (!all_of(autoPolicy(triProperties.size()), triPropertiesD.begin(), - triPropertiesD.end(), CheckProperties({numSets}))) { - MarkFailure(Error::TRI_PROPERTIES_OUT_OF_BOUNDS); - return nextMeshID; - }; - } - - VecDH> face2face(halfedge_.size(), {-1, -1}); - VecDH triArea(NumTri()); - for_each_n(autoPolicy(halfedge_.size()), zip(face2face.begin(), countAt(0)), - halfedge_.size(), - CoplanarEdge({triArea.ptrD(), halfedge_.cptrD(), vertPos_.cptrD(), - triPropertiesD.cptrD(), propertiesD.cptrD(), - propertyToleranceD.cptrD(), numProps, precision_})); - - Graph graph; - for (int i = 0; i < NumTri(); ++i) { - graph.add_nodes(i); - } - for (int i = 0; i < face2face.size(); ++i) { - const thrust::pair edge = face2face[i]; - if (edge.first < 0) continue; - graph.add_edge(edge.first, edge.second); - } - - std::vector components; - const int numComponent = ConnectedComponents(components, graph); - - std::vector comp2tri(numComponent, -1); - for (int tri = 0; tri < NumTri(); ++tri) { - const int comp = components[tri]; - const int current = comp2tri[comp]; - if (current < 0 || triArea[tri] > triArea[current]) { - comp2tri[comp] = tri; - triArea[comp] = triArea[tri]; - } - } - - VecDH& triBary = meshRelation_.triBary; - std::map, int> triVert2bary; - - for (int tri = 0; tri < NumTri(); ++tri) { - const int refTri = comp2tri[components[tri]]; - if (refTri == tri) continue; - - glm::mat3 triPos; - for (int i : {0, 1, 2}) { - const int vert = halfedge_[3 * refTri + i].startVert; - triPos[i] = vertPos_[vert]; - triVert2bary[{refTri, vert}] = i - 3; - } - - glm::ivec3 vertBary; - bool coplanar = true; - for (int i : {0, 1, 2}) { - const int vert = halfedge_[3 * tri + i].startVert; - if (triVert2bary.find({refTri, vert}) == triVert2bary.end()) { - const glm::vec3 uvw = - GetBarycentric(vertPos_[vert], triPos, precision_); - if (isnan(uvw[0])) { - coplanar = false; - triVert2bary[{refTri, vert}] = -4; - break; - } - triVert2bary[{refTri, vert}] = meshRelation_.barycentric.size(); - meshRelation_.barycentric.push_back(uvw); - } - const int bary = triVert2bary[{refTri, vert}]; - if (bary < -3) { - coplanar = false; - break; - } - vertBary[i] = bary; - } - - if (coplanar) { - BaryRef& ref = triBary[tri]; - ref.tri = refTri; - ref.vertBary = vertBary; - } - } - - return nextMeshID; -} - -/** - * Create the halfedge_ data structure from an input triVerts array like Mesh. - */ -void Manifold::Impl::CreateHalfedges(const VecDH& triVerts) { - const int numTri = triVerts.size(); - const int numEdge = 3 * numTri / 2; - // drop the old value first to avoid copy - halfedge_.resize(0); - halfedge_.resize(2 * numEdge); - VecDH edge(2 * numEdge); - VecDH ids(2 * numEdge); - auto policy = autoPolicy(numTri); - sequence(policy, ids.begin(), ids.end()); - for_each_n(policy, zip(countAt(0), triVerts.begin()), numTri, - Tri2Halfedges({halfedge_.ptrD(), edge.ptrD()})); - // Stable sort is required here so that halfedges from the same face are - // paired together (the triangles were created in face order). In some - // degenerate situations the triangulator can add the same internal edge in - // two different faces, causing this edge to not be 2-manifold. These are - // fixed by duplicating verts in SimplifyTopology. - stable_sort_by_key(policy, edge.begin(), edge.end(), ids.begin()); - // Once sorted, the first half of the range is the forward halfedges, which - // correspond to their backward pair at the same offset in the second half - // of the range. - for_each_n(policy, countAt(0), numEdge, - LinkHalfedges({halfedge_.ptrD(), ids.ptrD(), numEdge})); -} - -/** - * Does a full recalculation of the face bounding boxes, including updating the - * collider, but does not resort the faces. - */ -void Manifold::Impl::Update() { - CalculateBBox(); - VecDH faceBox; - VecDH faceMorton; - GetFaceBoxMorton(faceBox, faceMorton); - collider_.UpdateBoxes(faceBox); -} - -void Manifold::Impl::MarkFailure(Error status) { - bBox_ = Box(); - vertPos_.resize(0); - halfedge_.resize(0); - vertNormal_.resize(0); - faceNormal_.resize(0); - halfedgeTangent_.resize(0); - meshRelation_ = MeshRelationD(); - status_ = status; -} - -Manifold::Impl Manifold::Impl::Transform(const glm::mat4x3& transform_) const { - if (transform_ == glm::mat4x3(1.0f)) return *this; - auto policy = autoPolicy(NumVert()); - Impl result; - result.meshids = meshids; - result.collider_ = collider_; - result.meshRelation_ = meshRelation_; - result.precision_ = precision_; - result.bBox_ = bBox_; - result.halfedge_ = halfedge_; - result.halfedgeTangent_ = halfedgeTangent_; - - result.vertPos_.resize(NumVert()); - result.faceNormal_.resize(faceNormal_.size()); - result.vertNormal_.resize(vertNormal_.size()); - transform(policy, vertPos_.begin(), vertPos_.end(), result.vertPos_.begin(), - Transform4x3({transform_})); - - glm::mat3 normalTransform = - glm::inverse(glm::transpose(glm::mat3(transform_))); - transform(policy, faceNormal_.begin(), faceNormal_.end(), - result.faceNormal_.begin(), TransformNormals({normalTransform})); - transform(policy, vertNormal_.begin(), vertNormal_.end(), - result.vertNormal_.begin(), TransformNormals({normalTransform})); - // This optimization does a cheap collider update if the transform is - // axis-aligned. - if (!result.collider_.Transform(transform_)) result.Update(); - - result.CalculateBBox(); - float scale = 0; - for (int i : {0, 1, 2}) - scale = - glm::max(scale, transform_[0][i] + transform_[1][i] + transform_[2][i]); - result.precision_ *= scale; - // Maximum of inherited precision loss and translational precision loss. - result.SetPrecision(result.precision_); - return result; -} - -/** - * Sets the precision based on the bounding box, and limits its minimum value by - * the optional input. - */ -void Manifold::Impl::SetPrecision(float minPrecision) { - precision_ = glm::max(minPrecision, kTolerance * bBox_.Scale()); - if (!glm::isfinite(precision_)) precision_ = -1; -} - -/** - * If face normals are already present, this function uses them to compute - * vertex normals (angle-weighted pseudo-normals); otherwise it also computes - * the face normals. Face normals are only calculated when needed because nearly - * degenerate faces will accrue rounding error, while the Boolean can retain - * their original normal, which is more accurate and can help with merging - * coplanar faces. - * - * If the face normals have been invalidated by an operation like Warp(), ensure - * you do faceNormal_.resize(0) before calling this function to force - * recalculation. - */ -void Manifold::Impl::CalculateNormals() { - vertNormal_.resize(NumVert()); - auto policy = autoPolicy(NumTri()); - fill(policy, vertNormal_.begin(), vertNormal_.end(), glm::vec3(0)); - bool calculateTriNormal = false; - if (faceNormal_.size() != NumTri()) { - faceNormal_.resize(NumTri()); - calculateTriNormal = true; - } - for_each_n( - policy, zip(faceNormal_.begin(), countAt(0)), NumTri(), - AssignNormals({vertNormal_.ptrD(), vertPos_.cptrD(), halfedge_.cptrD(), - precision_, calculateTriNormal})); - for_each(policy, vertNormal_.begin(), vertNormal_.end(), Normalize()); -} - -/** - * Remaps all the contained meshIDs to new unique values to represent new - * instances of these meshes. - */ -void Manifold::Impl::IncrementMeshIDs(int start, int length) { - VecDH& triBary = meshRelation_.triBary; - ASSERT(start >= 0 && length >= 0 && start + length <= triBary.size(), - logicErr, "out of bounds"); - const auto policy = autoPolicy(length); - HashTable meshidTable(std::max(16u, meshids * 2)); - - auto begin = triBary.begin() + start; - auto end = begin + length; - while (1) { - for_each(policy, begin, end, MarkMeshID({meshidTable.D()})); - if (!meshidTable.Full()) break; - meshidTable = HashTable(meshidTable.Size() * 2); - } - inclusive_scan( - autoPolicy(meshidTable.Size()), meshidTable.GetValueStore().begin(), - meshidTable.GetValueStore().end(), meshidTable.GetValueStore().begin()); - const int numMeshIDs = meshidTable.GetValueStore().back(); - const int meshIDstart = Manifold::Impl::meshIDCounter_.fetch_add( - numMeshIDs, std::memory_order_relaxed); - // We do start - 1 because the inclusive scan makes our first index 1 instead - // of 0. - for_each(policy, begin, end, UpdateMeshID({meshidTable.D(), meshIDstart})); -} - -/** - * Returns a sparse array of the bounding box overlaps between the edges of the - * input manifold, Q and the faces of this manifold. Returned indices only - * point to forward halfedges. - */ -SparseIndices Manifold::Impl::EdgeCollisions(const Impl& Q) const { - VecDH edges = CreateTmpEdges(Q.halfedge_); - const int numEdge = edges.size(); - VecDH QedgeBB(numEdge); - auto policy = autoPolicy(numEdge); - for_each_n(policy, zip(QedgeBB.begin(), edges.cbegin()), numEdge, - EdgeBox({Q.vertPos_.cptrD()})); - - SparseIndices q1p2 = collider_.Collisions(QedgeBB); - - for_each(policy, q1p2.begin(0), q1p2.end(0), ReindexEdge({edges.cptrD()})); - return q1p2; -} - -/** - * Returns a sparse array of the input vertices that project inside the XY - * bounding boxes of the faces of this manifold. - */ -SparseIndices Manifold::Impl::VertexCollisionsZ( - const VecDH& vertsIn) const { - return collider_.Collisions(vertsIn); -} -} // namespace manifold diff --git a/IfcPlusPlus/src/external/manifold/src/impl.h b/IfcPlusPlus/src/external/manifold/src/impl.h deleted file mode 100644 index a4319c166..000000000 --- a/IfcPlusPlus/src/external/manifold/src/impl.h +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright 2021 The Manifold Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once -#include "collider.h" -#include "manifold.h" -#include "optional_assert.h" -#include "shared.h" -#include "sparse.h" -#include "utils.h" -#include "vec_dh.h" - -namespace manifold { - -/** @ingroup Private */ -struct Manifold::Impl { - struct MeshRelationD { - VecDH barycentric; - VecDH triBary; - /// The meshID of this Manifold if it is an original; -1 otherwise. - int originalID = -1; - }; - - Box bBox_; - float precision_ = -1; - Error status_ = Error::MANIFOLD_NO_ERROR; - VecDH vertPos_; - VecDH halfedge_; - VecDH vertNormal_; - VecDH faceNormal_; - VecDH halfedgeTangent_; - MeshRelationD meshRelation_; - Collider collider_; - unsigned int meshids = 1; - - static std::atomic meshIDCounter_; - - Impl() {} - enum class Shape { TETRAHEDRON, CUBE, OCTAHEDRON }; - Impl(Shape); - - Impl(const Mesh&, - const std::vector& triProperties = std::vector(), - const std::vector& properties = std::vector(), - const std::vector& propertyTolerance = std::vector()); - - int InitializeNewReference( - const std::vector& triProperties = std::vector(), - const std::vector& properties = std::vector(), - const std::vector& propertyTolerance = std::vector()); - - void RemoveUnreferencedVerts(VecDH& triVerts); - void ReinitializeReference(int meshID); - void CreateHalfedges(const VecDH& triVerts); - void CalculateNormals(); - void IncrementMeshIDs(int start, int length); - - void Update(); - void MarkFailure(Error status); - Impl Transform(const glm::mat4x3& transform) const; - SparseIndices EdgeCollisions(const Impl& B) const; - SparseIndices VertexCollisionsZ(const VecDH& vertsIn) const; - - bool IsEmpty() const { return NumVert() == 0; } - int NumVert() const { return vertPos_.size(); } - int NumEdge() const { return halfedge_.size() / 2; } - int NumTri() const { return halfedge_.size() / 3; } - - // properties.cu - Properties GetProperties() const; - Curvature GetCurvature() const; - void CalculateBBox(); - bool IsFinite() const; - bool IsIndexInBounds(const VecDH& triVerts) const; - void SetPrecision(float minPrecision = -1); - bool IsManifold() const; - bool Is2Manifold() const; - bool MatchesTriNormals() const; - int NumDegenerateTris() const; - - // sort.cu - void Finish(); - void SortVerts(); - void ReindexVerts(const VecDH& vertNew2Old, int numOldVert); - void GetFaceBoxMorton(VecDH& faceBox, VecDH& faceMorton) const; - void SortFaces(VecDH& faceBox, VecDH& faceMorton); - void GatherFaces(const VecDH& faceNew2Old); - void GatherFaces(const Impl& old, const VecDH& faceNew2Old); - - // face_op.cu - void Face2Tri(const VecDH& faceEdge, const VecDH& faceRef, - const VecDH& halfedgeBary); - Polygons Face2Polygons(int face, glm::mat3x2 projection, - const VecDH& faceEdge) const; - - // edge_op.cu - void SimplifyTopology(); - void DedupeEdge(int edge); - void CollapseEdge(int edge); - void RecursiveEdgeSwap(int edge); - void RemoveIfFolded(int edge); - void PairUp(int edge0, int edge1); - void UpdateVert(int vert, int startEdge, int endEdge); - void FormLoop(int current, int end); - void CollapseTri(const glm::ivec3& triEdge); - - // smoothing.cu - void CreateTangents(const std::vector&); - MeshRelationD Subdivide(int n); - void Refine(int n); -}; -} // namespace manifold diff --git a/IfcPlusPlus/src/external/manifold/src/manifold.cpp b/IfcPlusPlus/src/external/manifold/src/manifold.cpp deleted file mode 100644 index e3b8f6c3b..000000000 --- a/IfcPlusPlus/src/external/manifold/src/manifold.cpp +++ /dev/null @@ -1,615 +0,0 @@ -// Copyright 2021 The Manifold Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "boolean3.h" -#include "csg_tree.h" -#include "impl.h" -#include "par.h" - -namespace { -using namespace manifold; -using namespace thrust::placeholders; - -ExecutionParams params; - -struct MakeTri { - const Halfedge* halfedges; - - __host__ __device__ void operator()(thrust::tuple inOut) { - glm::ivec3& tri = thrust::get<0>(inOut); - const int face = 3 * thrust::get<1>(inOut); - - for (int i : {0, 1, 2}) { - tri[i] = halfedges[face + i].startVert; - } - } -}; - -Manifold Halfspace(Box bBox, glm::vec3 normal, float originOffset) { - normal = glm::normalize(normal); - Manifold cutter = - Manifold::Cube(glm::vec3(2.0f), true).Translate({1.0f, 0.0f, 0.0f}); - float size = glm::length(bBox.Center() - normal * originOffset) + - 0.5f * glm::length(bBox.Size()); - cutter = cutter.Scale(glm::vec3(size)).Translate({originOffset, 0.0f, 0.0f}); - float yDeg = glm::degrees(-glm::asin(normal.z)); - float zDeg = glm::degrees(glm::atan(normal.y, normal.x)); - return cutter.Rotate(0.0f, yDeg, zDeg); -} -} // namespace - -namespace manifold { - -/** - * Construct an empty Manifold. - * - */ -Manifold::Manifold() : pNode_{std::make_shared()} {} -Manifold::~Manifold() = default; -Manifold::Manifold(Manifold&&) noexcept = default; -Manifold& Manifold::operator=(Manifold&&) noexcept = default; - -Manifold::Manifold(const Manifold& other) : pNode_(other.pNode_) {} - -Manifold::Manifold(std::shared_ptr pNode) : pNode_(pNode) {} - -Manifold::Manifold(std::shared_ptr pImpl_) - : pNode_(std::make_shared(pImpl_)) {} - -Manifold& Manifold::operator=(const Manifold& other) { - if (this != &other) { - pNode_ = other.pNode_; - } - return *this; -} - -CsgLeafNode& Manifold::GetCsgLeafNode() const { - if (pNode_->GetNodeType() != CsgNodeType::LEAF) { - pNode_ = pNode_->ToLeafNode(); - } - return *std::static_pointer_cast(pNode_); -} - -/** - * Convert a Mesh into a Manifold. Will return an empty Manifold - * and set an Error Status if the Mesh is not an oriented 2-manifold. Will - * collapse degenerate triangles and unnecessary vertices. - * - * The three optional inputs should all be specified if any are. These define - * any properties you may have on this mesh. These properties are not saved in - * the Manifold, but rather used to determine which coplanar triangles can be - * safely merged due to all properties being colinear. Any edges that define - * property boundaries will be retained in the output of arbitrary Boolean - * operations so that these properties can be properly reapplied to the result - * using the MeshRelation. - * - * @param mesh The input Mesh. - * @param triProperties A vector of the same length as triVerts, filled with - * references to the properties index. Note the same vertex can have different - * properties in different triangles. - * @param properties A vector whose length is the largest index in - * triProperties times the length of propertyTolerance (the number of - * properties). Think of it as a property matrix indexed as [index * - * numProperties + propertyNum]. - * @param propertyTolerance A vector of precision values for each property. - * This is the amount of interpolation error allowed before two neighboring - * triangles are considered not coplanar. A good place to start is 1e-5 times - * the largest value you expect this property to take. - */ -Manifold::Manifold(const Mesh& mesh, - const std::vector& triProperties, - const std::vector& properties, - const std::vector& propertyTolerance) - : pNode_(std::make_shared(std::make_shared( - mesh, triProperties, properties, propertyTolerance))) {} - -/** - * This returns a Mesh of simple vectors of vertices and triangles suitable for - * saving or other operations outside of the context of this library. - */ -Mesh Manifold::GetMesh() const { - const Impl& impl = *GetCsgLeafNode().GetImpl(); - - Mesh result; - result.vertPos.insert(result.vertPos.end(), impl.vertPos_.begin(), - impl.vertPos_.end()); - result.vertNormal.insert(result.vertNormal.end(), impl.vertNormal_.begin(), - impl.vertNormal_.end()); - result.halfedgeTangent.insert(result.halfedgeTangent.end(), - impl.halfedgeTangent_.begin(), - impl.halfedgeTangent_.end()); - - result.triVerts.resize(NumTri()); - // note that `triVerts` is `std::vector`, so we cannot use thrust::device - thrust::for_each_n(thrust::host, zip(result.triVerts.begin(), countAt(0)), - NumTri(), MakeTri({impl.halfedge_.cptrH()})); - - return result; -} - -MeshGL Manifold::GetMeshGL() const { - const Impl& impl = *GetCsgLeafNode().GetImpl(); - - const int numVert = NumVert(); - const int numTri = NumTri(); - - MeshGL out; - out.vertPos.resize(3 * numVert); - out.vertNormal.resize(3 * numVert); - out.triVerts.resize(3 * numTri); - for (int i = 0; i < numVert; ++i) { - const glm::vec3 v = impl.vertPos_[i]; - out.vertPos[3 * i] = v.x; - out.vertPos[3 * i + 1] = v.y; - out.vertPos[3 * i + 2] = v.z; - const glm::vec3 n = impl.vertNormal_[i]; - out.vertNormal[3 * i] = n.x; - out.vertNormal[3 * i + 1] = n.y; - out.vertNormal[3 * i + 2] = n.z; - } - for (int i = 0; i < numTri * 3; ++i) { - out.triVerts[i] = impl.halfedge_[i].startVert; - } - const int numHalfedge = impl.halfedgeTangent_.size(); - out.halfedgeTangent.resize(4 * numHalfedge); - for (int i = 0; i < numHalfedge; ++i) { - const glm::vec4 t = impl.halfedgeTangent_[i]; - out.halfedgeTangent[4 * i] = t.x; - out.halfedgeTangent[4 * i + 1] = t.y; - out.halfedgeTangent[4 * i + 2] = t.z; - out.halfedgeTangent[4 * i + 3] = t.w; - } - - return out; -} - -int Manifold::circularSegments_ = 0; -float Manifold::circularAngle_ = 10.0f; -float Manifold::circularEdgeLength_ = 1.0f; - -/** - * Sets an angle constraint the default number of circular segments for the - * Cylinder(), Sphere(), and Revolve() constructors. The number of segments will - * be rounded up to the nearest factor of four. - * - * @param angle The minimum angle in degrees between consecutive segments. The - * angle will increase if the the segments hit the minimum edge length. Default - * is 10 degrees. - */ -void Manifold::SetMinCircularAngle(float angle) { - if (angle <= 0) return; - Manifold::circularAngle_ = angle; -} - -/** - * Sets a length constraint the default number of circular segments for the - * Cylinder(), Sphere(), and Revolve() constructors. The number of segments will - * be rounded up to the nearest factor of four. - * - * @param length The minimum length of segments. The length will - * increase if the the segments hit the minimum angle. Default is 1.0. - */ -void Manifold::SetMinCircularEdgeLength(float length) { - if (length <= 0) return; - Manifold::circularEdgeLength_ = length; -} - -/** - * Sets the default number of circular segments for the - * Cylinder(), Sphere(), and Revolve() constructors. Overrides the edge length - * and angle constraints and sets the number of segments to exactly this value. - * - * @param number Number of circular segments. Default is 0, meaning no - * constraint is applied. - */ -void Manifold::SetCircularSegments(int number) { - if (number < 3 && number != 0) return; - Manifold::circularSegments_ = number; -} - -/** - * Determine the result of the SetMinCircularAngle(), - * SetMinCircularEdgeLength(), and SetCircularSegments() defaults. - * - * @param radius For a given radius of circle, determine how many default - * segments there will be. - */ -int Manifold::GetCircularSegments(float radius) { - if (Manifold::circularSegments_ > 0) return Manifold::circularSegments_; - int nSegA = 360.0f / Manifold::circularAngle_; - int nSegL = 2.0f * radius * glm::pi() / Manifold::circularEdgeLength_; - int nSeg = fmin(nSegA, nSegL) + 3; - nSeg -= nSeg % 4; - return nSeg; -} - -/** - * Does the Manifold have any triangles? - */ -bool Manifold::IsEmpty() const { return GetCsgLeafNode().GetImpl()->IsEmpty(); } -/** - * Returns the reason for an input Mesh producing an empty Manifold. This Status - * only applies to Manifolds newly-created from an input Mesh - once they are - * combined into a new Manifold via operations, the status reverts to NO_ERROR, - * simply processing the problem mesh as empty. Likewise, empty meshes may still - * show NO_ERROR, for instance if they are small enough relative to their - * precision to be collapsed to nothing. - */ -Manifold::Error Manifold::Status() const { - return GetCsgLeafNode().GetImpl()->status_; -} -/** - * The number of vertices in the Manifold. - */ -int Manifold::NumVert() const { return GetCsgLeafNode().GetImpl()->NumVert(); } -/** - * The number of edges in the Manifold. - */ -int Manifold::NumEdge() const { return GetCsgLeafNode().GetImpl()->NumEdge(); } -/** - * The number of triangles in the Manifold. - */ -int Manifold::NumTri() const { return GetCsgLeafNode().GetImpl()->NumTri(); } - -/** - * Returns the axis-aligned bounding box of all the Manifold's vertices. - */ -Box Manifold::BoundingBox() const { return GetCsgLeafNode().GetImpl()->bBox_; } - -/** - * Returns the precision of this Manifold's vertices, which tracks the - * approximate rounding error over all the transforms and operations that have - * led to this state. Any triangles that are colinear within this precision are - * considered degenerate and removed. This is the value of ε defining - * [ε-valid](https://github.com/elalish/manifold/wiki/Manifold-Library#definition-of-%CE%B5-valid). - */ -float Manifold::Precision() const { - return GetCsgLeafNode().GetImpl()->precision_; -} - -/** - * The genus is a topological property of the manifold, representing the number - * of "handles". A sphere is 0, torus 1, etc. It is only meaningful for a single - * mesh, so it is best to call Decompose() first. - */ -int Manifold::Genus() const { - int chi = NumVert() - NumEdge() + NumTri(); - return 1 - chi / 2; -} - -/** - * Returns the surface area and volume of the manifold. These properties are - * clamped to zero for a given face if they are within the Precision(). This - * means degenerate manifolds can by identified by testing these properties as - * == 0. - */ -Properties Manifold::GetProperties() const { - return GetCsgLeafNode().GetImpl()->GetProperties(); -} - -/** - * Curvature is the inverse of the radius of curvature, and signed such that - * positive is convex and negative is concave. There are two orthogonal - * principal curvatures at any point on a manifold, with one maximum and the - * other minimum. Gaussian curvature is their product, while mean - * curvature is their sum. This approximates them for every vertex (returned as - * vectors in the structure) and also returns their minimum and maximum values. - */ -Curvature Manifold::GetCurvature() const { - return GetCsgLeafNode().GetImpl()->GetCurvature(); -} - -/** - * Gets the relationship to the previous meshes, for the purpose of assigning - * properties like texture coordinates. The triBary vector is the same length as - * Mesh.triVerts: BaryRef.originalID indicates the source mesh and BaryRef.tri - * is that mesh's triangle index to which these barycentric coordinates refer. - * BaryRef.vertBary gives an index for each vertex into the barycentric vector - * if that index is >= 0, indicating it is a new vertex. If the index is < 0, - * this indicates it is an original vertex, the index + 3 vert of the referenced - * triangle. - * - * BaryRef.meshID is a unique ID to the particular instance of a given mesh. For - * instance, if you want to convert the triangle mesh to a polygon mesh, all the - * triangles from a given face will have the same .meshID and .tri values. - */ -MeshRelation Manifold::GetMeshRelation() const { - MeshRelation out; - const auto& relation = GetCsgLeafNode().GetImpl()->meshRelation_; - out.triBary.insert(out.triBary.end(), relation.triBary.begin(), - relation.triBary.end()); - out.barycentric.insert(out.barycentric.end(), relation.barycentric.begin(), - relation.barycentric.end()); - return out; -} - -/** - * If this mesh is an original, this returns its meshID that can be referenced - * by product manifolds' MeshRelation. If this manifold is a product, this - * returns -1. - */ -int Manifold::OriginalID() const { - return GetCsgLeafNode().GetImpl()->meshRelation_.originalID; -} - -/** - * If you copy a manifold, but you want this new copy to have new properties - * (e.g. a different UV mapping), you can reset its meshIDs to a new original, - * meaning it will now be referenced by its descendents instead of the meshes it - * was built from, allowing you to differentiate the copies when applying your - * properties to the final result. - * - * This function also condenses all coplanar faces in the relation, and - * collapses those edges. If you want to have inconsistent properties across - * these faces, meaning you want to preserve some of these edges, you should - * instead call GetMesh(), calculate your properties and use these to construct - * a new manifold. - */ -Manifold Manifold::AsOriginal() const { - auto newImpl = std::make_shared(*GetCsgLeafNode().GetImpl()); - newImpl->InitializeNewReference(); - newImpl->SimplifyTopology(); - newImpl->Finish(); - return Manifold(std::make_shared(newImpl)); -} - -/** - * Should always be true. Also checks saneness of the internal data structures. - */ -bool Manifold::IsManifold() const { - return GetCsgLeafNode().GetImpl()->Is2Manifold(); -} - -/** - * The triangle normal vectors are saved over the course of operations rather - * than recalculated to avoid rounding error. This checks that triangles still - * match their normal vectors within Precision(). - */ -bool Manifold::MatchesTriNormals() const { - return GetCsgLeafNode().GetImpl()->MatchesTriNormals(); -} - -/** - * The number of triangles that are colinear within Precision(). This library - * attempts to remove all of these, but it cannot always remove all of them - * without changing the mesh by too much. - */ -int Manifold::NumDegenerateTris() const { - return GetCsgLeafNode().GetImpl()->NumDegenerateTris(); -} - -/** - * This is a checksum-style verification of the collider, simply returning the - * total number of edge-face bounding box overlaps between this and other. - * - * @param other A Manifold to overlap with. - */ -int Manifold::NumOverlaps(const Manifold& other) const { - SparseIndices overlaps = GetCsgLeafNode().GetImpl()->EdgeCollisions( - *other.GetCsgLeafNode().GetImpl()); - int num_overlaps = overlaps.size(); - - overlaps = other.GetCsgLeafNode().GetImpl()->EdgeCollisions( - *GetCsgLeafNode().GetImpl()); - return num_overlaps += overlaps.size(); -} - -/** - * Move this Manifold in space. This operation can be chained. Transforms are - * combined and applied lazily. - * - * @param v The vector to add to every vertex. - */ -Manifold Manifold::Translate(glm::vec3 v) const { - return Manifold(pNode_->Translate(v)); -} - -/** - * Scale this Manifold in space. This operation can be chained. Transforms are - * combined and applied lazily. - * - * @param v The vector to multiply every vertex by per component. - */ -Manifold Manifold::Scale(glm::vec3 v) const { - return Manifold(pNode_->Scale(v)); -} - -/** - * Applies an Euler angle rotation to the manifold, first about the X axis, then - * Y, then Z, in degrees. We use degrees so that we can minimize rounding error, - * and eliminate it completely for any multiples of 90 degrees. Additionally, - * more efficient code paths are used to update the manifold when the transforms - * only rotate by multiples of 90 degrees. This operation can be chained. - * Transforms are combined and applied lazily. - * - * @param xDegrees First rotation, degrees about the X-axis. - * @param yDegrees Second rotation, degrees about the Y-axis. - * @param zDegrees Third rotation, degrees about the Z-axis. - */ -Manifold Manifold::Rotate(float xDegrees, float yDegrees, - float zDegrees) const { - return Manifold(pNode_->Rotate(xDegrees, yDegrees, zDegrees)); -} - -/** - * Transform this Manifold in space. The first three columns form a 3x3 matrix - * transform and the last is a translation vector. This operation can be - * chained. Transforms are combined and applied lazily. - * - * @param m The affine transform matrix to apply to all the vertices. - */ -Manifold Manifold::Transform(const glm::mat4x3& m) const { - return Manifold(pNode_->Transform(m)); -} - -/** - * This function does not change the topology, but allows the vertices to be - * moved according to any arbitrary input function. It is easy to create a - * function that warps a geometrically valid object into one which overlaps, but - * that is not checked here, so it is up to the user to choose their function - * with discretion. - * - * @param warpFunc A function that modifies a given vertex position. - */ -Manifold Manifold::Warp(std::function warpFunc) const { - auto pImpl = std::make_shared(*GetCsgLeafNode().GetImpl()); - thrust::for_each_n(thrust::host, pImpl->vertPos_.begin(), NumVert(), - warpFunc); - pImpl->Update(); - pImpl->faceNormal_.resize(0); // force recalculation of triNormal - pImpl->CalculateNormals(); - pImpl->SetPrecision(); - return Manifold(std::make_shared(pImpl)); -} - -/** - * Increase the density of the mesh by splitting every edge into n pieces. For - * instance, with n = 2, each triangle will be split into 4 triangles. These - * will all be coplanar (and will not be immediately collapsed) unless the - * Mesh/Manifold has halfedgeTangents specified (e.g. from the Smooth() - * constructor), in which case the new vertices will be moved to the - * interpolated surface according to their barycentric coordinates. - * - * @param n The number of pieces to split every edge into. Must be > 1. - */ -Manifold Manifold::Refine(int n) const { - auto pImpl = std::make_shared(*GetCsgLeafNode().GetImpl()); - pImpl->Refine(n); - return Manifold(std::make_shared(pImpl)); -} - -/** - * The central operation of this library: the Boolean combines two manifolds - * into another by calculating their intersections and removing the unused - * portions. - * [ε-valid](https://github.com/elalish/manifold/wiki/Manifold-Library#definition-of-%CE%B5-valid) - * inputs will produce ε-valid output. ε-invalid input may fail - * triangulation. - * - * These operations are optimized to produce nearly-instant results if either - * input is empty or their bounding boxes do not overlap. - * - * @param second The other Manifold. - * @param op The type of operation to perform. - */ -Manifold Manifold::Boolean(const Manifold& second, OpType op) const { - std::vector> children({pNode_, second.pNode_}); - return Manifold(std::make_shared(children, op)); -} - -Manifold Manifold::BatchBoolean(const std::vector& manifolds, - OpType op) { - if (manifolds.size() == 0) - return Manifold(); - else if (manifolds.size() == 1) - return manifolds[0]; - std::vector> children; - children.reserve(manifolds.size()); - for (const auto& m : manifolds) children.push_back(m.pNode_); - return Manifold(std::make_shared(children, op)); -} - -/** - * Shorthand for Boolean Union. - */ -Manifold Manifold::operator+(const Manifold& Q) const { - return Boolean(Q, OpType::ADD); -} - -/** - * Shorthand for Boolean Union assignment. - */ -Manifold& Manifold::operator+=(const Manifold& Q) { - *this = *this + Q; - return *this; -} - -/** - * Shorthand for Boolean Difference. - */ -Manifold Manifold::operator-(const Manifold& Q) const { - return Boolean(Q, OpType::SUBTRACT); -} - -/** - * Shorthand for Boolean Difference assignment. - */ -Manifold& Manifold::operator-=(const Manifold& Q) { - *this = *this - Q; - return *this; -} - -/** - * Shorthand for Boolean Intersection. - */ -Manifold Manifold::operator^(const Manifold& Q) const { - return Boolean(Q, OpType::INTERSECT); -} - -/** - * Shorthand for Boolean Intersection assignment. - */ -Manifold& Manifold::operator^=(const Manifold& Q) { - *this = *this ^ Q; - return *this; -} - -/** - * Split cuts this manifold in two using the cutter manifold. The first result - * is the intersection, second is the difference. This is more efficient than - * doing them separately. - * - * @param cutter - */ -std::pair Manifold::Split(const Manifold& cutter) const { - auto impl1 = GetCsgLeafNode().GetImpl(); - auto impl2 = cutter.GetCsgLeafNode().GetImpl(); - - Boolean3 boolean(*impl1, *impl2, OpType::SUBTRACT); - auto result1 = std::make_shared( - std::make_unique(boolean.Result(OpType::INTERSECT))); - auto result2 = std::make_shared( - std::make_unique(boolean.Result(OpType::SUBTRACT))); - return std::make_pair(Manifold(result1), Manifold(result2)); -} - -/** - * Convenient version of Split() for a half-space. - * - * @param normal This vector is normal to the cutting plane and its length does - * not matter. The first result is in the direction of this vector, the second - * result is on the opposite side. - * @param originOffset The distance of the plane from the origin in the - * direction of the normal vector. - */ -std::pair Manifold::SplitByPlane(glm::vec3 normal, - float originOffset) const { - return Split(Halfspace(BoundingBox(), normal, originOffset)); -} - -/** - * Identical to SplitByPlane(), but calculating and returning only the first - * result. - * - * @param normal This vector is normal to the cutting plane and its length does - * not matter. The result is in the direction of this vector from the plane. - * @param originOffset The distance of the plane from the origin in the - * direction of the normal vector. - */ -Manifold Manifold::TrimByPlane(glm::vec3 normal, float originOffset) const { - return *this ^ Halfspace(BoundingBox(), normal, originOffset); -} - -ExecutionParams& ManifoldParams() { return params; } -} // namespace manifold diff --git a/IfcPlusPlus/src/external/manifold/src/manifold/CMakeLists.txt b/IfcPlusPlus/src/external/manifold/src/manifold/CMakeLists.txt deleted file mode 100644 index 4625f0e58..000000000 --- a/IfcPlusPlus/src/external/manifold/src/manifold/CMakeLists.txt +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 The Manifold Authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -project (manifold) - -file(GLOB_RECURSE SOURCE_FILES CONFIGURE_DEPENDS *.cpp) -add_library(${PROJECT_NAME} ${SOURCE_FILES}) - -if(MANIFOLD_USE_CUDA) - set_source_files_properties( ${SOURCE_FILES} PROPERTIES LANGUAGE CUDA) - set_property(TARGET ${PROJECT_NAME} PROPERTY CUDA_ARCHITECTURES 61) -endif() - -target_include_directories(${PROJECT_NAME} PUBLIC ${PROJECT_SOURCE_DIR}/include ) -target_link_libraries(${PROJECT_NAME} - PUBLIC utilities - PRIVATE collider polygon ${MANIFOLD_INCLUDE} graphlite -) - -target_compile_features(${PROJECT_NAME} - PUBLIC cxx_std_14 - PRIVATE cxx_std_17 -) - diff --git a/IfcPlusPlus/src/external/manifold/src/manifold/include/manifold.h b/IfcPlusPlus/src/external/manifold/src/manifold/include/manifold.h deleted file mode 100644 index 9fe9d038e..000000000 --- a/IfcPlusPlus/src/external/manifold/src/manifold/include/manifold.h +++ /dev/null @@ -1,196 +0,0 @@ -// Copyright 2021 The Manifold Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once -#include -#include - -#include "public.h" - -namespace manifold { - -/** - * @ingroup Debug - * - * Allows modification of the assertions checked in MANIFOLD_DEBUG mode. - * - * @return ExecutionParams& - */ -ExecutionParams& ManifoldParams(); - -class CsgNode; -class CsgLeafNode; - -/** @defgroup Core - * @brief The central classes of the library - * @{ - */ -class Manifold { - public: - /** @name Creation - * Constructors - */ - ///@{ - Manifold(); - ~Manifold(); - Manifold(const Manifold& other); - Manifold& operator=(const Manifold& other); - Manifold(Manifold&&) noexcept; - Manifold& operator=(Manifold&&) noexcept; - - Manifold( - const Mesh&, - const std::vector& triProperties = std::vector(), - const std::vector& properties = std::vector(), - const std::vector& propertyTolerance = std::vector()); - - static Manifold Smooth(const Mesh&, - const std::vector& sharpenedEdges = {}); - static Manifold Tetrahedron(); - static Manifold Cube(glm::vec3 size = glm::vec3(1.0f), bool center = false); - static Manifold Cylinder(float height, float radiusLow, - float radiusHigh = -1.0f, int circularSegments = 0, - bool center = false); - static Manifold Sphere(float radius, int circularSegments = 0); - static Manifold Extrude(Polygons crossSection, float height, - int nDivisions = 0, float twistDegrees = 0.0f, - glm::vec2 scaleTop = glm::vec2(1.0f)); - static Manifold Revolve(const Polygons& crossSection, - int circularSegments = 0); - ///@} - - /** @name Topological - * No geometric calculations. - */ - ///@{ - static Manifold Compose(const std::vector&); - std::vector Decompose() const; - ///@} - - /** @name Defaults - * These static properties control how circular shapes are quantized by - * default on construction. If circularSegments is specified, it takes - * precedence. If it is zero, then instead the minimum is used of the segments - * calculated based on edge length and angle, rounded up to the nearest - * multiple of four. To get numbers not divisible by four, circularSegments - * must be specified. - */ - ///@{ - static void SetMinCircularAngle(float degrees); - static void SetMinCircularEdgeLength(float length); - static void SetCircularSegments(int number); - static int GetCircularSegments(float radius); - ///@} - - /** @name Information - * Details of the manifold - */ - ///@{ - Mesh GetMesh() const; - MeshGL GetMeshGL() const; - bool IsEmpty() const; - enum class Error { - MANIFOLD_NO_ERROR, - NON_FINITE_VERTEX, - NOT_MANIFOLD, - VERTEX_INDEX_OUT_OF_BOUNDS, - PROPERTIES_WRONG_LENGTH, - TRI_PROPERTIES_WRONG_LENGTH, - TRI_PROPERTIES_OUT_OF_BOUNDS, - }; - Error Status() const; - int NumVert() const; - int NumEdge() const; - int NumTri() const; - Box BoundingBox() const; - float Precision() const; - int Genus() const; - Properties GetProperties() const; - Curvature GetCurvature() const; - ///@} - - /** @name Relation - * Details of the manifold's relation to its input meshes, for the purposes - * of reapplying mesh properties. - */ - ///@{ - MeshRelation GetMeshRelation() const; - int OriginalID() const; - Manifold AsOriginal() const; - ///@} - - /** @name Modification - */ - ///@{ - Manifold Translate(glm::vec3) const; - Manifold Scale(glm::vec3) const; - Manifold Rotate(float xDegrees, float yDegrees = 0.0f, - float zDegrees = 0.0f) const; - Manifold Transform(const glm::mat4x3&) const; - Manifold Warp(std::function) const; - Manifold Refine(int) const; - // Manifold RefineToLength(float); - // Manifold RefineToPrecision(float); - ///@} - - /** @name Boolean - * Combine two manifolds - */ - ///@{ - /** - * Boolean operation type: ADD (Union), SUBTRACT (Difference), and INTERSECT. - */ - enum class OpType { ADD, SUBTRACT, INTERSECT }; - Manifold Boolean(const Manifold& second, OpType op) const; - static Manifold BatchBoolean(const std::vector& manifolds, - OpType op); - // Boolean operation shorthand - Manifold operator+(const Manifold&) const; // ADD (Union) - Manifold& operator+=(const Manifold&); - Manifold operator-(const Manifold&) const; // SUBTRACT (Difference) - Manifold& operator-=(const Manifold&); - Manifold operator^(const Manifold&) const; // INTERSECT - Manifold& operator^=(const Manifold&); - std::pair Split(const Manifold&) const; - std::pair SplitByPlane(glm::vec3 normal, - float originOffset) const; - Manifold TrimByPlane(glm::vec3 normal, float originOffset) const; - ///@} - - /** @name Testing hooks - * These are just for internal testing. - */ - ///@{ - bool IsManifold() const; - bool MatchesTriNormals() const; - int NumDegenerateTris() const; - int NumOverlaps(const Manifold& second) const; - ///@} - - struct Impl; - - private: - Manifold(std::shared_ptr pNode_); - Manifold(std::shared_ptr pImpl_); - - mutable std::shared_ptr pNode_; - - CsgLeafNode& GetCsgLeafNode() const; - - static int circularSegments_; - static float circularAngle_; - static float circularEdgeLength_; -}; -/** @} */ -} // namespace manifold diff --git a/IfcPlusPlus/src/external/manifold/src/manifold/src/boolean3.cpp b/IfcPlusPlus/src/external/manifold/src/manifold/src/boolean3.cpp deleted file mode 100644 index a60a495ae..000000000 --- a/IfcPlusPlus/src/external/manifold/src/manifold/src/boolean3.cpp +++ /dev/null @@ -1,617 +0,0 @@ -// Copyright 2021 The Manifold Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "boolean3.h" - -#include - -#include "par.h" - -using namespace manifold; - -namespace { - -// These two functions (Interpolate and Intersect) are the only places where -// floating-point operations take place in the whole Boolean function. These are -// carefully designed to minimize rounding error and to eliminate it at edge -// cases to ensure consistency. - -__host__ __device__ glm::vec2 Interpolate(glm::vec3 pL, glm::vec3 pR, float x) { - float dxL = x - pL.x; - float dxR = x - pR.x; -#ifdef MANIFOLD_DEBUG - if (dxL * dxR > 0) printf("Not in domain!\n"); -#endif - bool useL = fabs(dxL) < fabs(dxR); - float lambda = (useL ? dxL : dxR) / (pR.x - pL.x); - if (!isfinite(lambda)) return glm::vec2(pL.y, pL.z); - glm::vec2 yz; - yz[0] = (useL ? pL.y : pR.y) + lambda * (pR.y - pL.y); - yz[1] = (useL ? pL.z : pR.z) + lambda * (pR.z - pL.z); - return yz; -} - -__host__ __device__ glm::vec4 Intersect(const glm::vec3 &pL, - const glm::vec3 &pR, - const glm::vec3 &qL, - const glm::vec3 &qR) { - float dyL = qL.y - pL.y; - float dyR = qR.y - pR.y; -#ifdef MANIFOLD_DEBUG - if (dyL * dyR > 0) printf("No intersection!\n"); -#endif - bool useL = fabs(dyL) < fabs(dyR); - float dx = pR.x - pL.x; - float lambda = (useL ? dyL : dyR) / (dyL - dyR); - if (!isfinite(lambda)) lambda = 0.0f; - glm::vec4 xyzz; - xyzz.x = (useL ? pL.x : pR.x) + lambda * dx; - float pDy = pR.y - pL.y; - float qDy = qR.y - qL.y; - bool useP = fabs(pDy) < fabs(qDy); - xyzz.y = (useL ? (useP ? pL.y : qL.y) : (useP ? pR.y : qR.y)) + - lambda * (useP ? pDy : qDy); - xyzz.z = (useL ? pL.z : pR.z) + lambda * (pR.z - pL.z); - xyzz.w = (useL ? qL.z : qR.z) + lambda * (qR.z - qL.z); - return xyzz; -} - -struct CopyFaceEdges { - // x can be either vert or edge (0 or 1). - thrust::pair pXq1; - const Halfedge *halfedgesQ; - - __host__ __device__ void operator()(thrust::tuple in) { - int idx = 3 * thrust::get<0>(in); - const int pX = thrust::get<1>(in); - const int q2 = thrust::get<2>(in); - - for (const int i : {0, 1, 2}) { - pXq1.first[idx + i] = pX; - const int q1 = 3 * q2 + i; - const Halfedge edge = halfedgesQ[q1]; - pXq1.second[idx + i] = edge.IsForward() ? q1 : edge.pairedHalfedge; - } - } -}; - -SparseIndices Filter11(const Manifold::Impl &inP, const Manifold::Impl &inQ, - const SparseIndices &p1q2, const SparseIndices &p2q1, - ExecutionPolicy policy) { - SparseIndices p1q1(3 * p1q2.size() + 3 * p2q1.size()); - for_each_n(policy, zip(countAt(0), p1q2.begin(0), p1q2.begin(1)), p1q2.size(), - CopyFaceEdges({p1q1.ptrDpq(), inQ.halfedge_.cptrD()})); - - p1q1.SwapPQ(); - for_each_n(policy, zip(countAt(p1q2.size()), p2q1.begin(1), p2q1.begin(0)), - p2q1.size(), - CopyFaceEdges({p1q1.ptrDpq(), inP.halfedge_.cptrD()})); - p1q1.SwapPQ(); - p1q1.Unique(policy); - return p1q1; -} - -__host__ __device__ bool Shadows(float p, float q, float dir) { - return p == q ? dir < 0 : p < q; -} - -/** - * Since this function is called from two different places, it is necessary that - * it returns identical results for identical input to keep consistency. - * Normally this is trivial as computers make floating-point errors, but are - * at least deterministic. However, in the case of CUDA, these functions can be - * compiled by two different compilers (for the CPU and GPU). We have found that - * the different compilers can cause slightly different rounding errors, so it - * is critical that the two places this function is called both use the same - * compiled function (they must agree on CPU or GPU). This is now taken care of - * by the shared policy_ member. - */ -__host__ __device__ thrust::pair Shadow01( - const int p0, const int q1, const glm::vec3 *vertPosP, - const glm::vec3 *vertPosQ, const Halfedge *halfedgeQ, const float expandP, - const glm::vec3 *normalP, const bool reverse) { - const int q1s = halfedgeQ[q1].startVert; - const int q1e = halfedgeQ[q1].endVert; - const float p0x = vertPosP[p0].x; - const float q1sx = vertPosQ[q1s].x; - const float q1ex = vertPosQ[q1e].x; - int s01 = reverse ? Shadows(q1sx, p0x, expandP * normalP[q1s].x) - - Shadows(q1ex, p0x, expandP * normalP[q1e].x) - : Shadows(p0x, q1ex, expandP * normalP[p0].x) - - Shadows(p0x, q1sx, expandP * normalP[p0].x); - glm::vec2 yz01(NAN); - - if (s01 != 0) { - yz01 = Interpolate(vertPosQ[q1s], vertPosQ[q1e], vertPosP[p0].x); - if (reverse) { - glm::vec3 diff = vertPosQ[q1s] - vertPosP[p0]; - const float start2 = glm::dot(diff, diff); - diff = vertPosQ[q1e] - vertPosP[p0]; - const float end2 = glm::dot(diff, diff); - const float dir = start2 < end2 ? normalP[q1s].y : normalP[q1e].y; - if (!Shadows(yz01[0], vertPosP[p0].y, expandP * dir)) s01 = 0; - } else { - if (!Shadows(vertPosP[p0].y, yz01[0], expandP * normalP[p0].y)) s01 = 0; - } - } - return thrust::make_pair(s01, yz01); -} - -__host__ __device__ int BinarySearch( - const thrust::pair keys, const int size, - const thrust::pair key) { - if (size <= 0) return -1; - int left = 0; - int right = size - 1; - int m; - thrust::pair keyM; - while (1) { - m = right - (right - left) / 2; - keyM = thrust::make_pair(keys.first[m], keys.second[m]); - if (left == right) break; - if (keyM > key) - right = m - 1; - else - left = m; - } - if (keyM == key) - return m; - else - return -1; -} - -struct Kernel11 { - const glm::vec3 *vertPosP; - const glm::vec3 *vertPosQ; - const Halfedge *halfedgeP; - const Halfedge *halfedgeQ; - float expandP; - const glm::vec3 *normalP; - - __host__ __device__ void operator()( - thrust::tuple inout) { - glm::vec4 &xyzz11 = thrust::get<0>(inout); - int &s11 = thrust::get<1>(inout); - const int p1 = thrust::get<2>(inout); - const int q1 = thrust::get<3>(inout); - - // For pRL[k], qRL[k], k==0 is the left and k==1 is the right. - int k = 0; - glm::vec3 pRL[2], qRL[2]; - // Either the left or right must shadow, but not both. This ensures the - // intersection is between the left and right. - bool shadows = false; - s11 = 0; - - const int p0[2] = {halfedgeP[p1].startVert, halfedgeP[p1].endVert}; - for (int i : {0, 1}) { - const auto syz01 = Shadow01(p0[i], q1, vertPosP, vertPosQ, halfedgeQ, - expandP, normalP, false); - const int s01 = syz01.first; - const glm::vec2 yz01 = syz01.second; - // If the value is NaN, then these do not overlap. - if (isfinite(yz01[0])) { - s11 += s01 * (i == 0 ? -1 : 1); - if (k < 2 && (k == 0 || (s01 != 0) != shadows)) { - shadows = s01 != 0; - pRL[k] = vertPosP[p0[i]]; - qRL[k] = glm::vec3(pRL[k].x, yz01); - ++k; - } - } - } - - const int q0[2] = {halfedgeQ[q1].startVert, halfedgeQ[q1].endVert}; - for (int i : {0, 1}) { - const auto syz10 = Shadow01(q0[i], p1, vertPosQ, vertPosP, halfedgeP, - expandP, normalP, true); - const int s10 = syz10.first; - const glm::vec2 yz10 = syz10.second; - // If the value is NaN, then these do not overlap. - if (isfinite(yz10[0])) { - s11 += s10 * (i == 0 ? -1 : 1); - if (k < 2 && (k == 0 || (s10 != 0) != shadows)) { - shadows = s10 != 0; - qRL[k] = vertPosQ[q0[i]]; - pRL[k] = glm::vec3(qRL[k].x, yz10); - ++k; - } - } - } - - if (s11 == 0) { // No intersection - xyzz11 = glm::vec4(NAN); - } else { -#ifdef MANIFOLD_DEBUG - // Assert left and right were both found - if (k != 2) { - printf("k = %d\n", k); - } -#endif - xyzz11 = Intersect(pRL[0], pRL[1], qRL[0], qRL[1]); - - const int p1s = halfedgeP[p1].startVert; - const int p1e = halfedgeP[p1].endVert; - glm::vec3 diff = vertPosP[p1s] - glm::vec3(xyzz11); - const float start2 = glm::dot(diff, diff); - diff = vertPosP[p1e] - glm::vec3(xyzz11); - const float end2 = glm::dot(diff, diff); - const float dir = start2 < end2 ? normalP[p1s].z : normalP[p1e].z; - - if (!Shadows(xyzz11.z, xyzz11.w, expandP * dir)) s11 = 0; - } - } -}; - -std::tuple, VecDH> Shadow11(SparseIndices &p1q1, - const Manifold::Impl &inP, - const Manifold::Impl &inQ, - float expandP, - ExecutionPolicy policy) { - VecDH s11(p1q1.size()); - VecDH xyzz11(p1q1.size()); - - for_each_n(policy, - zip(xyzz11.begin(), s11.begin(), p1q1.begin(0), p1q1.begin(1)), - p1q1.size(), - Kernel11({inP.vertPos_.cptrD(), inQ.vertPos_.cptrD(), - inP.halfedge_.cptrD(), inQ.halfedge_.cptrD(), expandP, - inP.vertNormal_.cptrD()})); - - p1q1.KeepFinite(xyzz11, s11); - - return std::make_tuple(s11, xyzz11); -}; - -struct Kernel02 { - const glm::vec3 *vertPosP; - const Halfedge *halfedgeQ; - const glm::vec3 *vertPosQ; - const bool forward; - const float expandP; - const glm::vec3 *vertNormalP; - - __host__ __device__ void operator()( - thrust::tuple inout) { - int &s02 = thrust::get<0>(inout); - float &z02 = thrust::get<1>(inout); - const int p0 = thrust::get<2>(inout); - const int q2 = thrust::get<3>(inout); - - // For yzzLR[k], k==0 is the left and k==1 is the right. - int k = 0; - glm::vec3 yzzRL[2]; - // Either the left or right must shadow, but not both. This ensures the - // intersection is between the left and right. - bool shadows = false; - int closestVert = -1; - float minMetric = std::numeric_limits::infinity(); - s02 = 0; - - const glm::vec3 posP = vertPosP[p0]; - for (const int i : {0, 1, 2}) { - const int q1 = 3 * q2 + i; - const Halfedge edge = halfedgeQ[q1]; - const int q1F = edge.IsForward() ? q1 : edge.pairedHalfedge; - - if (!forward) { - const int qVert = halfedgeQ[q1F].startVert; - const glm::vec3 diff = posP - vertPosQ[qVert]; - const float metric = glm::dot(diff, diff); - if (metric < minMetric) { - minMetric = metric; - closestVert = qVert; - } - } - - const auto syz01 = Shadow01(p0, q1F, vertPosP, vertPosQ, halfedgeQ, - expandP, vertNormalP, !forward); - const int s01 = syz01.first; - const glm::vec2 yz01 = syz01.second; - // If the value is NaN, then these do not overlap. - if (isfinite(yz01[0])) { - s02 += s01 * (forward == edge.IsForward() ? -1 : 1); - if (k < 2 && (k == 0 || (s01 != 0) != shadows)) { - shadows = s01 != 0; - yzzRL[k++] = glm::vec3(yz01[0], yz01[1], yz01[1]); - } - } - } - - if (s02 == 0) { // No intersection - z02 = NAN; - } else { -#ifdef MANIFOLD_DEBUG - // Assert left and right were both found - if (k != 2) { - printf("k = %d\n", k); - } -#endif - glm::vec3 vertPos = vertPosP[p0]; - z02 = Interpolate(yzzRL[0], yzzRL[1], vertPos.y)[1]; - if (forward) { - if (!Shadows(vertPos.z, z02, expandP * vertNormalP[p0].z)) s02 = 0; - } else { - // ASSERT(closestVert != -1, topologyErr, "No closest vert"); - if (!Shadows(z02, vertPos.z, expandP * vertNormalP[closestVert].z)) - s02 = 0; - } - } - } -}; - -std::tuple, VecDH> Shadow02(const Manifold::Impl &inP, - const Manifold::Impl &inQ, - SparseIndices &p0q2, bool forward, - float expandP, - ExecutionPolicy policy) { - VecDH s02(p0q2.size()); - VecDH z02(p0q2.size()); - - auto vertNormalP = - forward ? inP.vertNormal_.cptrD() : inQ.vertNormal_.cptrD(); - for_each_n( - policy, - zip(s02.begin(), z02.begin(), p0q2.begin(!forward), p0q2.begin(forward)), - p0q2.size(), - Kernel02({inP.vertPos_.cptrD(), inQ.halfedge_.cptrD(), - inQ.vertPos_.cptrD(), forward, expandP, vertNormalP})); - - p0q2.KeepFinite(z02, s02); - - return std::make_tuple(s02, z02); -}; - -struct Kernel12 { - const thrust::pair p0q2; - const int *s02; - const float *z02; - const int size02; - const thrust::pair p1q1; - const int *s11; - const glm::vec4 *xyzz11; - const int size11; - const Halfedge *halfedgesP; - const Halfedge *halfedgesQ; - const glm::vec3 *vertPosP; - const bool forward; - - __host__ __device__ void operator()( - thrust::tuple inout) { - int &x12 = thrust::get<0>(inout); - glm::vec3 &v12 = thrust::get<1>(inout); - const int p1 = thrust::get<2>(inout); - const int q2 = thrust::get<3>(inout); - - // For xzyLR-[k], k==0 is the left and k==1 is the right. - int k = 0; - glm::vec3 xzyLR0[2]; - glm::vec3 xzyLR1[2]; - // Either the left or right must shadow, but not both. This ensures the - // intersection is between the left and right. - bool shadows = false; - x12 = 0; - - const Halfedge edge = halfedgesP[p1]; - - for (int vert : {edge.startVert, edge.endVert}) { - const auto key = - forward ? thrust::make_pair(vert, q2) : thrust::make_pair(q2, vert); - const int idx = BinarySearch(p0q2, size02, key); - if (idx != -1) { - const int s = s02[idx]; - x12 += s * ((vert == edge.startVert) == forward ? 1 : -1); - if (k < 2 && (k == 0 || (s != 0) != shadows)) { - shadows = s != 0; - xzyLR0[k] = vertPosP[vert]; - thrust::swap(xzyLR0[k].y, xzyLR0[k].z); - xzyLR1[k] = xzyLR0[k]; - xzyLR1[k][1] = z02[idx]; - k++; - } - } - } - - for (const int i : {0, 1, 2}) { - const int q1 = 3 * q2 + i; - const Halfedge edge = halfedgesQ[q1]; - const int q1F = edge.IsForward() ? q1 : edge.pairedHalfedge; - const auto key = - forward ? thrust::make_pair(p1, q1F) : thrust::make_pair(q1F, p1); - const int idx = BinarySearch(p1q1, size11, key); - if (idx != -1) { // s is implicitly zero for anything not found - const int s = s11[idx]; - x12 -= s * (edge.IsForward() ? 1 : -1); - if (k < 2 && (k == 0 || (s != 0) != shadows)) { - shadows = s != 0; - const glm::vec4 xyzz = xyzz11[idx]; - xzyLR0[k][0] = xyzz.x; - xzyLR0[k][1] = xyzz.z; - xzyLR0[k][2] = xyzz.y; - xzyLR1[k] = xzyLR0[k]; - xzyLR1[k][1] = xyzz.w; - if (!forward) thrust::swap(xzyLR0[k][1], xzyLR1[k][1]); - k++; - } - } - } - - if (x12 == 0) { // No intersection - v12 = glm::vec3(NAN); - } else { -#ifdef MANIFOLD_DEBUG - // Assert left and right were both found - if (k != 2) { - printf("k = %d\n", k); - } -#endif - const glm::vec4 xzyy = - Intersect(xzyLR0[0], xzyLR0[1], xzyLR1[0], xzyLR1[1]); - v12.x = xzyy[0]; - v12.y = xzyy[2]; - v12.z = xzyy[1]; - } - } -}; - -std::tuple, VecDH> Intersect12( - const Manifold::Impl &inP, const Manifold::Impl &inQ, const VecDH &s02, - const SparseIndices &p0q2, const VecDH &s11, const SparseIndices &p1q1, - const VecDH &z02, const VecDH &xyzz11, - SparseIndices &p1q2, bool forward, ExecutionPolicy policy) { - VecDH x12(p1q2.size()); - VecDH v12(p1q2.size()); - - for_each_n( - policy, - zip(x12.begin(), v12.begin(), p1q2.begin(!forward), p1q2.begin(forward)), - p1q2.size(), - Kernel12({p0q2.ptrDpq(), s02.ptrD(), z02.cptrD(), p0q2.size(), - p1q1.ptrDpq(), s11.ptrD(), xyzz11.cptrD(), p1q1.size(), - inP.halfedge_.cptrD(), inQ.halfedge_.cptrD(), - inP.vertPos_.cptrD(), forward})); - - p1q2.KeepFinite(v12, x12); - - return std::make_tuple(x12, v12); -}; - -VecDH Winding03(const Manifold::Impl &inP, SparseIndices &p0q2, - VecDH &s02, bool reverse, ExecutionPolicy policy) { - // verts that are not shadowed (not in p0q2) have winding number zero. - VecDH w03(inP.NumVert(), 0); - - if (!is_sorted(policy, p0q2.begin(reverse), p0q2.end(reverse))) - sort_by_key(policy, p0q2.begin(reverse), p0q2.end(reverse), s02.begin()); - VecDH w03val(w03.size()); - VecDH w03vert(w03.size()); - // sum known s02 values into w03 (winding number) - auto endPair = reduce_by_key< - thrust::pair>( - policy, p0q2.begin(reverse), p0q2.end(reverse), s02.begin(), - w03vert.begin(), w03val.begin()); - scatter(policy, w03val.begin(), endPair.second, w03vert.begin(), w03.begin()); - - if (reverse) - transform(policy, w03.begin(), w03.end(), w03.begin(), - thrust::negate()); - return w03; -}; -} // namespace - -namespace manifold { -Boolean3::Boolean3(const Manifold::Impl &inP, const Manifold::Impl &inQ, - Manifold::OpType op) - : inP_(inP), - inQ_(inQ), - expandP_(op == Manifold::OpType::ADD ? 1.0 : -1.0), - policy_(autoPolicy(glm::max(inP.NumEdge(), inQ.NumEdge()))) { - // Symbolic perturbation: - // Union -> expand inP - // Difference, Intersection -> contract inP - -#ifdef MANIFOLD_DEBUG - Timer broad; - broad.Start(); -#endif - - if (inP.IsEmpty() || inQ.IsEmpty() || !inP.bBox_.DoesOverlap(inQ.bBox_)) { - PRINT("No overlap, early out"); - w03_.resize(inP.NumVert(), 0); - w30_.resize(inQ.NumVert(), 0); - return; - } - - // Level 3 - // Find edge-triangle overlaps (broad phase) - p1q2_ = inQ_.EdgeCollisions(inP_); - p2q1_ = inP_.EdgeCollisions(inQ_); - - policy_ = autoPolicy(glm::max(p1q2_.size(), p2q1_.size())); - p1q2_.Sort(policy_); - PRINT("p1q2 size = " << p1q2_.size()); - - p2q1_.SwapPQ(); - p2q1_.Sort(policy_); - PRINT("p2q1 size = " << p2q1_.size()); - - // Level 2 - // Find vertices that overlap faces in XY-projection - SparseIndices p0q2 = inQ.VertexCollisionsZ(inP.vertPos_); - p0q2.Sort(policy_); - PRINT("p0q2 size = " << p0q2.size()); - - SparseIndices p2q0 = inP.VertexCollisionsZ(inQ.vertPos_); - p2q0.SwapPQ(); - p2q0.Sort(policy_); - PRINT("p2q0 size = " << p2q0.size()); - - // Find involved edge pairs from Level 3 - SparseIndices p1q1 = Filter11(inP_, inQ_, p1q2_, p2q1_, policy_); - PRINT("p1q1 size = " << p1q1.size()); - -#ifdef MANIFOLD_DEBUG - broad.Stop(); - Timer intersections; - intersections.Start(); -#endif - - // Level 2 - // Build up XY-projection intersection of two edges, including the z-value for - // each edge, keeping only those whose intersection exists. - VecDH s11; - VecDH xyzz11; - std::tie(s11, xyzz11) = Shadow11(p1q1, inP, inQ, expandP_, policy_); - PRINT("s11 size = " << s11.size()); - - // Build up Z-projection of vertices onto triangles, keeping only those that - // fall inside the triangle. - VecDH s02; - VecDH z02; - std::tie(s02, z02) = Shadow02(inP, inQ, p0q2, true, expandP_, policy_); - PRINT("s02 size = " << s02.size()); - - VecDH s20; - VecDH z20; - std::tie(s20, z20) = Shadow02(inQ, inP, p2q0, false, expandP_, policy_); - PRINT("s20 size = " << s20.size()); - - // Level 3 - // Build up the intersection of the edges and triangles, keeping only those - // that intersect, and record the direction the edge is passing through the - // triangle. - std::tie(x12_, v12_) = Intersect12(inP, inQ, s02, p0q2, s11, p1q1, z02, - xyzz11, p1q2_, true, policy_); - PRINT("x12 size = " << x12_.size()); - - std::tie(x21_, v21_) = Intersect12(inQ, inP, s20, p2q0, s11, p1q1, z20, - xyzz11, p2q1_, false, policy_); - PRINT("x21 size = " << x21_.size()); - - // Sum up the winding numbers of all vertices. - w03_ = Winding03(inP, p0q2, s02, false, policy_); - - w30_ = Winding03(inQ, p2q0, s20, true, policy_); - -#ifdef MANIFOLD_DEBUG - intersections.Stop(); - - if (ManifoldParams().verbose) { - broad.Print("Broad phase"); - intersections.Print("Intersections"); - MemUsage(); - } -#endif -} -} // namespace manifold diff --git a/IfcPlusPlus/src/external/manifold/src/manifold/src/boolean3.h b/IfcPlusPlus/src/external/manifold/src/manifold/src/boolean3.h deleted file mode 100644 index 7a4f864ab..000000000 --- a/IfcPlusPlus/src/external/manifold/src/manifold/src/boolean3.h +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2020 The Manifold Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once -#include "impl.h" - -#ifdef MANIFOLD_DEBUG -#define PRINT(msg) \ - if (ManifoldParams().verbose) std::cout << msg << std::endl; -#else -#define PRINT(msg) -#endif - -/** - * The notation in these files is abbreviated due to the complexity of the - * functions involved. The key is that the input manifolds are P and Q, while - * the output is R, and these letters in both upper and lower case refer to - * these objects. Operations are based on dimensionality: vert: 0, edge: 1, - * face: 2, solid: 3. X denotes a winding-number type quantity from the source - * paper of this algorithm, while S is closely related but includes only the - * subset of X values which "shadow" (are on the correct side of). - * - * Nearly everything here are sparse arrays, where for instance each pair in - * p2q1 refers to a face index of P interacting with a halfedge index of Q. - * Adjacent arrays like x21 refer to the values of X corresponding to each - * sparse index pair. - * - * Note many functions are designed to work symmetrically, for instance for both - * p2q1 and p1q2. Inside of these functions P and Q are marked as though the - * function is forwards, but it may include a Boolean "reverse" that indicates P - * and Q have been swapped. - */ - -namespace manifold { - -/** @ingroup Private */ -class Boolean3 { - public: - Boolean3(const Manifold::Impl& inP, const Manifold::Impl& inQ, - Manifold::OpType op); - Manifold::Impl Result(Manifold::OpType op) const; - - private: - const Manifold::Impl &inP_, &inQ_; - const float expandP_; - SparseIndices p1q2_, p2q1_; - VecDH x12_, x21_, w03_, w30_; - VecDH v12_, v21_; - ExecutionPolicy policy_; -}; -} // namespace manifold diff --git a/IfcPlusPlus/src/external/manifold/src/manifold/src/boolean_result.cpp b/IfcPlusPlus/src/external/manifold/src/manifold/src/boolean_result.cpp deleted file mode 100644 index 1f039f7a8..000000000 --- a/IfcPlusPlus/src/external/manifold/src/manifold/src/boolean_result.cpp +++ /dev/null @@ -1,700 +0,0 @@ -// Copyright 2021 The Manifold Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include - -#include "boolean3.h" -#include "par.h" -#include "polygon.h" - -using namespace manifold; -using namespace thrust::placeholders; - -namespace { - -struct AbsSum : public thrust::binary_function { - __host__ __device__ int operator()(int a, int b) { return abs(a) + abs(b); } -}; - -struct DuplicateVerts { - glm::vec3 *vertPosR; - - __host__ __device__ void operator()(thrust::tuple in) { - int inclusion = abs(thrust::get<0>(in)); - int vertR = thrust::get<1>(in); - glm::vec3 vertPosP = thrust::get<2>(in); - - for (int i = 0; i < inclusion; ++i) { - vertPosR[vertR + i] = vertPosP; - } - } -}; - -struct CountVerts { - int *count; - const int *inclusion; - - __host__ __device__ void operator()(const Halfedge &edge) { - AtomicAdd(count[edge.face], glm::abs(inclusion[edge.startVert])); - } -}; - -struct CountNewVerts { - int *countP; - int *countQ; - const Halfedge *halfedges; - - __host__ __device__ void operator()(thrust::tuple in) { - int edgeP = thrust::get<0>(in); - int faceQ = thrust::get<1>(in); - int inclusion = glm::abs(thrust::get<2>(in)); - - AtomicAdd(countQ[faceQ], inclusion); - const Halfedge half = halfedges[edgeP]; - AtomicAdd(countP[half.face], inclusion); - AtomicAdd(countP[halfedges[half.pairedHalfedge].face], inclusion); - } -}; - -struct NotZero : public thrust::unary_function { - __host__ __device__ int operator()(int x) const { return x > 0 ? 1 : 0; } -}; - -std::tuple, VecDH> SizeOutput( - Manifold::Impl &outR, const Manifold::Impl &inP, const Manifold::Impl &inQ, - const VecDH &i03, const VecDH &i30, const VecDH &i12, - const VecDH &i21, const SparseIndices &p1q2, const SparseIndices &p2q1, - bool invertQ, ExecutionPolicy policy) { - VecDH sidesPerFacePQ(inP.NumTri() + inQ.NumTri(), 0); - auto sidesPerFaceP = sidesPerFacePQ.ptrD(); - auto sidesPerFaceQ = sidesPerFacePQ.ptrD() + inP.NumTri(); - - for_each(policy, inP.halfedge_.begin(), inP.halfedge_.end(), - CountVerts({sidesPerFaceP, i03.cptrD()})); - for_each(policy, inQ.halfedge_.begin(), inQ.halfedge_.end(), - CountVerts({sidesPerFaceQ, i30.cptrD()})); - for_each_n( - policy, zip(p1q2.begin(0), p1q2.begin(1), i12.begin()), i12.size(), - CountNewVerts({sidesPerFaceP, sidesPerFaceQ, inP.halfedge_.cptrD()})); - for_each_n( - policy, zip(p2q1.begin(1), p2q1.begin(0), i21.begin()), i21.size(), - CountNewVerts({sidesPerFaceQ, sidesPerFaceP, inQ.halfedge_.cptrD()})); - - VecDH facePQ2R(inP.NumTri() + inQ.NumTri() + 1, 0); - auto keepFace = - thrust::make_transform_iterator(sidesPerFacePQ.begin(), NotZero()); - inclusive_scan(policy, keepFace, keepFace + sidesPerFacePQ.size(), - facePQ2R.begin() + 1); - int numFaceR = facePQ2R.back(); - facePQ2R.resize(inP.NumTri() + inQ.NumTri()); - - outR.faceNormal_.resize(numFaceR); - auto next = copy_if( - policy, inP.faceNormal_.begin(), inP.faceNormal_.end(), keepFace, - outR.faceNormal_.begin(), thrust::identity()); - if (invertQ) { - auto start = thrust::make_transform_iterator(inQ.faceNormal_.begin(), - thrust::negate()); - auto end = thrust::make_transform_iterator(inQ.faceNormal_.end(), - thrust::negate()); - copy_if(policy, start, end, - keepFace + inP.NumTri(), next, - thrust::identity()); - } else { - copy_if( - policy, inQ.faceNormal_.begin(), inQ.faceNormal_.end(), - keepFace + inP.NumTri(), next, thrust::identity()); - } - - auto newEnd = remove( - policy, sidesPerFacePQ.begin(), sidesPerFacePQ.end(), 0); - VecDH faceEdge(newEnd - sidesPerFacePQ.begin() + 1, 0); - inclusive_scan(policy, sidesPerFacePQ.begin(), newEnd, faceEdge.begin() + 1); - outR.halfedge_.resize(faceEdge.back()); - - return std::make_tuple(faceEdge, facePQ2R); -} - -struct EdgePos { - int vert; - float edgePos; - bool isStart; -}; - -void AddNewEdgeVerts( - std::map> &edgesP, - std::map, std::vector> &edgesNew, - const SparseIndices &p1q2, const VecDH &i12, const VecDH &v12R, - const VecDH &halfedgeP, bool forward) { - // For each edge of P that intersects a face of Q (p1q2), add this vertex to - // P's corresponding edge vector and to the two new edges, which are - // intersections between the face of Q and the two faces of P attached to the - // edge. The direction and duplicity are given by i12, while v12R remaps to - // the output vert index. When forward is false, all is reversed. - const VecDH &p1 = p1q2.Get(!forward); - const VecDH &q2 = p1q2.Get(forward); - for (int i = 0; i < p1q2.size(); ++i) { - const int edgeP = p1[i]; - const int faceQ = q2[i]; - const int vert = v12R[i]; - const int inclusion = i12[i]; - - auto &edgePosP = edgesP[edgeP]; - - Halfedge halfedge = halfedgeP[edgeP]; - std::pair key = {halfedgeP[halfedge.pairedHalfedge].face, faceQ}; - if (!forward) std::swap(key.first, key.second); - auto &edgePosRight = edgesNew[key]; - - key = {halfedge.face, faceQ}; - if (!forward) std::swap(key.first, key.second); - auto &edgePosLeft = edgesNew[key]; - - EdgePos edgePos = {vert, 0.0f, inclusion < 0}; - EdgePos edgePosRev = edgePos; - edgePosRev.isStart = !edgePos.isStart; - - for (int j = 0; j < glm::abs(inclusion); ++j) { - edgePosP.push_back(edgePos); - edgePosRight.push_back(forward ? edgePos : edgePosRev); - edgePosLeft.push_back(forward ? edgePosRev : edgePos); - ++edgePos.vert; - ++edgePosRev.vert; - } - } -} - -std::vector PairUp(std::vector &edgePos) { - // Pair start vertices with end vertices to form edges. The choice of pairing - // is arbitrary for the manifoldness guarantee, but must be ordered to be - // geometrically valid. If the order does not go start-end-start-end... then - // the input and output are not geometrically valid and this algorithm becomes - // a heuristic. - ASSERT(edgePos.size() % 2 == 0, topologyErr, - "Non-manifold edge! Not an even number of points."); - int nEdges = edgePos.size() / 2; - auto middle = std::partition(edgePos.begin(), edgePos.end(), - [](EdgePos x) { return x.isStart; }); - ASSERT(middle - edgePos.begin() == nEdges, topologyErr, "Non-manifold edge!"); - auto cmp = [](EdgePos a, EdgePos b) { return a.edgePos < b.edgePos; }; - std::sort(edgePos.begin(), middle, cmp); - std::sort(middle, edgePos.end(), cmp); - std::vector edges; - for (int i = 0; i < nEdges; ++i) - edges.push_back({edgePos[i].vert, edgePos[i + nEdges].vert, -1, -1}); - return edges; -} - -// A Ref carries the reference of a halfedge's startVert back to the input -// manifolds. PQ is 0 if the halfedge comes from triangle tri of P, and 1 for Q. -// vert is 0, 1, or 2 to denote which vertex of tri it is, and -1 if it is new. -struct Ref { - int PQ, tri, vert; -}; - -void AppendPartialEdges(Manifold::Impl &outR, VecDH &wholeHalfedgeP, - VecDH &facePtrR, - std::map> &edgesP, - VecDH &halfedgeRef, const Manifold::Impl &inP, - const VecDH &i03, const VecDH &vP2R, - const VecDH::IterC faceP2R, bool forward) { - // Each edge in the map is partially retained; for each of these, look up - // their original verts and include them based on their winding number (i03), - // while remapping them to the output using vP2R. Use the verts position - // projected along the edge vector to pair them up, then distribute these - // edges to their faces. - VecDH &halfedgeR = outR.halfedge_; - const VecDH &vertPosP = inP.vertPos_; - const VecDH &halfedgeP = inP.halfedge_; - - for (auto &value : edgesP) { - const int edgeP = value.first; - std::vector &edgePosP = value.second; - - const Halfedge &halfedge = halfedgeP[edgeP]; - wholeHalfedgeP[edgeP] = false; - wholeHalfedgeP[halfedge.pairedHalfedge] = false; - - const int vStart = halfedge.startVert; - const int vEnd = halfedge.endVert; - const glm::vec3 edgeVec = vertPosP[vEnd] - vertPosP[vStart]; - // Fill in the edge positions of the old points. - for (EdgePos &edge : edgePosP) { - edge.edgePos = glm::dot(outR.vertPos_[edge.vert], edgeVec); - } - - int inclusion = i03[vStart]; - bool reversed = inclusion < 0; - EdgePos edgePos = {vP2R[vStart], - glm::dot(outR.vertPos_[vP2R[vStart]], edgeVec), - inclusion > 0}; - for (int j = 0; j < glm::abs(inclusion); ++j) { - edgePosP.push_back(edgePos); - ++edgePos.vert; - } - - inclusion = i03[vEnd]; - reversed |= inclusion < 0; - edgePos = {vP2R[vEnd], glm::dot(outR.vertPos_[vP2R[vEnd]], edgeVec), - inclusion < 0}; - for (int j = 0; j < glm::abs(inclusion); ++j) { - edgePosP.push_back(edgePos); - ++edgePos.vert; - } - - // sort edges into start/end pairs along length - std::vector edges = PairUp(edgePosP); - - // add halfedges to result - const int faceLeftP = halfedge.face; - const int faceLeft = faceP2R[faceLeftP]; - const int faceRightP = halfedgeP[halfedge.pairedHalfedge].face; - const int faceRight = faceP2R[faceRightP]; - // Negative inclusion means the halfedges are reversed, which means our - // reference is now to the endVert instead of the startVert, which is one - // position advanced CCW. This is only valid if this is a retained vert; it - // will be ignored later if the vert is new. - const Ref forwardRef = {forward ? 0 : 1, faceLeftP, - (edgeP + (reversed ? 1 : 0)) % 3}; - const Ref backwardRef = { - forward ? 0 : 1, faceRightP, - (halfedge.pairedHalfedge + (reversed ? 1 : 0)) % 3}; - - for (Halfedge e : edges) { - const int forwardEdge = facePtrR[faceLeft]++; - const int backwardEdge = facePtrR[faceRight]++; - - e.face = faceLeft; - e.pairedHalfedge = backwardEdge; - halfedgeR[forwardEdge] = e; - halfedgeRef[forwardEdge] = forwardRef; - - std::swap(e.startVert, e.endVert); - e.face = faceRight; - e.pairedHalfedge = forwardEdge; - halfedgeR[backwardEdge] = e; - halfedgeRef[backwardEdge] = backwardRef; - } - } -} - -void AppendNewEdges( - Manifold::Impl &outR, VecDH &facePtrR, - std::map, std::vector> &edgesNew, - VecDH &halfedgeRef, const VecDH &facePQ2R, const int numFaceP) { - // Pair up each edge's verts and distribute to faces based on indices in key. - VecDH &halfedgeR = outR.halfedge_; - VecDH &vertPosR = outR.vertPos_; - - for (auto &value : edgesNew) { - const int faceP = value.first.first; - const int faceQ = value.first.second; - std::vector &edgePos = value.second; - - Box bbox; - for (auto edge : edgePos) { - bbox.Union(vertPosR[edge.vert]); - } - const glm::vec3 size = bbox.Size(); - // Order the points along their longest dimension. - const int i = (size.x > size.y && size.x > size.z) ? 0 - : size.y > size.z ? 1 - : 2; - for (auto &edge : edgePos) { - edge.edgePos = vertPosR[edge.vert][i]; - } - - // sort edges into start/end pairs along length. - std::vector edges = PairUp(edgePos); - - // add halfedges to result - const int faceLeft = facePQ2R[faceP]; - const int faceRight = facePQ2R[numFaceP + faceQ]; - const Ref forwardRef = {0, faceP, -4}; - const Ref backwardRef = {1, faceQ, -4}; - for (Halfedge e : edges) { - const int forwardEdge = facePtrR[faceLeft]++; - const int backwardEdge = facePtrR[faceRight]++; - - e.face = faceLeft; - e.pairedHalfedge = backwardEdge; - halfedgeR[forwardEdge] = e; - halfedgeRef[forwardEdge] = forwardRef; - - std::swap(e.startVert, e.endVert); - e.face = faceRight; - e.pairedHalfedge = forwardEdge; - halfedgeR[backwardEdge] = e; - halfedgeRef[backwardEdge] = backwardRef; - } - } -} - -struct DuplicateHalfedges { - Halfedge *halfedgesR; - Ref *halfedgeRef; - int *facePtr; - const Halfedge *halfedgesP; - const int *i03; - const int *vP2R; - const int *faceP2R; - const bool forward; - - __host__ __device__ void operator()(thrust::tuple in) { - if (!thrust::get<0>(in)) return; - Halfedge halfedge = thrust::get<1>(in); - if (!halfedge.IsForward()) return; - const int edgeP = thrust::get<2>(in); - - const int inclusion = i03[halfedge.startVert]; - if (inclusion == 0) return; - if (inclusion < 0) { // reverse - int tmp = halfedge.startVert; - halfedge.startVert = halfedge.endVert; - halfedge.endVert = tmp; - } - halfedge.startVert = vP2R[halfedge.startVert]; - halfedge.endVert = vP2R[halfedge.endVert]; - const int faceLeftP = halfedge.face; - halfedge.face = faceP2R[faceLeftP]; - const int faceRightP = halfedgesP[halfedge.pairedHalfedge].face; - const int faceRight = faceP2R[faceRightP]; - // Negative inclusion means the halfedges are reversed, which means our - // reference is now to the endVert instead of the startVert, which is one - // position advanced CCW. - const Ref forwardRef = {forward ? 0 : 1, faceLeftP, - (edgeP + (inclusion < 0 ? 1 : 0)) % 3}; - const Ref backwardRef = { - forward ? 0 : 1, faceRightP, - (halfedge.pairedHalfedge + (inclusion < 0 ? 1 : 0)) % 3}; - - for (int i = 0; i < glm::abs(inclusion); ++i) { - int forwardEdge = AtomicAdd(facePtr[halfedge.face], 1); - int backwardEdge = AtomicAdd(facePtr[faceRight], 1); - halfedge.pairedHalfedge = backwardEdge; - - halfedgesR[forwardEdge] = halfedge; - halfedgesR[backwardEdge] = {halfedge.endVert, halfedge.startVert, - forwardEdge, faceRight}; - halfedgeRef[forwardEdge] = forwardRef; - halfedgeRef[backwardEdge] = backwardRef; - - ++halfedge.startVert; - ++halfedge.endVert; - } - } -}; - -void AppendWholeEdges(Manifold::Impl &outR, VecDH &facePtrR, - VecDH &halfedgeRef, const Manifold::Impl &inP, - const VecDH wholeHalfedgeP, const VecDH &i03, - const VecDH &vP2R, const int *faceP2R, bool forward, - ExecutionPolicy policy) { - for_each_n(policy, - zip(wholeHalfedgeP.begin(), inP.halfedge_.begin(), countAt(0)), - inP.halfedge_.size(), - DuplicateHalfedges({outR.halfedge_.ptrD(), halfedgeRef.ptrD(), - facePtrR.ptrD(), inP.halfedge_.cptrD(), - i03.cptrD(), vP2R.cptrD(), faceP2R, forward})); -} - -struct CreateBarycentric { - glm::vec3 *barycentricR; - BaryRef *faceRef; - int *idx; - - const int offsetQ; - const int firstNewVert; - const glm::vec3 *vertPosR; - const glm::vec3 *vertPosP; - const glm::vec3 *vertPosQ; - const Halfedge *halfedgeP; - const Halfedge *halfedgeQ; - const BaryRef *triBaryP; - const BaryRef *triBaryQ; - const glm::vec3 *barycentricP; - const glm::vec3 *barycentricQ; - const bool invertQ; - const float precision; - - __host__ __device__ void operator()( - thrust::tuple inOut) { - int &halfedgeBary = thrust::get<0>(inOut); - const Ref halfedgeRef = thrust::get<1>(inOut); - const Halfedge halfedgeR = thrust::get<2>(inOut); - - const glm::vec3 *barycentric = - halfedgeRef.PQ == 0 ? barycentricP : barycentricQ; - const int tri = halfedgeRef.tri; - const BaryRef oldRef = halfedgeRef.PQ == 0 ? triBaryP[tri] : triBaryQ[tri]; - - faceRef[halfedgeR.face] = oldRef; - - if (halfedgeRef.PQ == 1) { - // Mark the meshID as coming from Q - faceRef[halfedgeR.face].meshID += offsetQ; - } - - if (halfedgeR.startVert < firstNewVert) { // retained vert - int i = halfedgeRef.vert; - const int bary = oldRef.vertBary[i]; - if (bary < 0) { - halfedgeBary = bary; - } else { - halfedgeBary = AtomicAdd(*idx, 1); - barycentricR[halfedgeBary] = barycentric[bary]; - } - } else { // new vert - halfedgeBary = AtomicAdd(*idx, 1); - - const glm::vec3 *vertPos = halfedgeRef.PQ == 0 ? vertPosP : vertPosQ; - const Halfedge *halfedge = halfedgeRef.PQ == 0 ? halfedgeP : halfedgeQ; - - glm::mat3 triPos; - for (int i : {0, 1, 2}) - triPos[i] = vertPos[halfedge[3 * tri + i].startVert]; - - glm::mat3 uvwOldTri; - for (int i : {0, 1, 2}) - uvwOldTri[i] = UVW(oldRef.vertBary[i], barycentric); - - const glm::vec3 uvw = - GetBarycentric(vertPosR[halfedgeR.startVert], triPos, precision); - barycentricR[halfedgeBary] = uvwOldTri * uvw; - } - } -}; - -std::pair, VecDH> CalculateMeshRelation( - Manifold::Impl &outR, const VecDH &halfedgeRef, - const Manifold::Impl &inP, const Manifold::Impl &inQ, int firstNewVert, - int numFaceR, bool invertQ, ExecutionPolicy policy) { - outR.meshRelation_.barycentric.resize(outR.halfedge_.size()); - VecDH faceRef(numFaceR); - VecDH halfedgeBary(halfedgeRef.size()); - - const int offsetQ = Manifold::Impl::meshIDCounter_; - VecDH idx(1, 0); - for_each_n( - policy, - zip(halfedgeBary.begin(), halfedgeRef.begin(), outR.halfedge_.cbegin()), - halfedgeRef.size(), - CreateBarycentric( - {outR.meshRelation_.barycentric.ptrD(), faceRef.ptrD(), idx.ptrD(), - offsetQ, firstNewVert, outR.vertPos_.cptrD(), inP.vertPos_.cptrD(), - inQ.vertPos_.cptrD(), inP.halfedge_.cptrD(), inQ.halfedge_.cptrD(), - inP.meshRelation_.triBary.cptrD(), inQ.meshRelation_.triBary.cptrD(), - inP.meshRelation_.barycentric.cptrD(), - inQ.meshRelation_.barycentric.cptrD(), invertQ, outR.precision_})); - outR.meshRelation_.barycentric.resize(idx[0]); - - return std::make_pair(faceRef, halfedgeBary); -} -} // namespace - -namespace manifold { - -Manifold::Impl Boolean3::Result(Manifold::OpType op) const { -#ifdef MANIFOLD_DEBUG - Timer assemble; - assemble.Start(); -#endif - - ASSERT((expandP_ > 0) == (op == Manifold::OpType::ADD), logicErr, - "Result op type not compatible with constructor op type."); - const int c1 = op == Manifold::OpType::INTERSECT ? 0 : 1; - const int c2 = op == Manifold::OpType::ADD ? 1 : 0; - const int c3 = op == Manifold::OpType::INTERSECT ? 1 : -1; - - if (w03_.size() == 0) { - if (w30_.size() != 0 && op == Manifold::OpType::ADD) { - return inQ_; - } - return Manifold::Impl(); - } else if (w30_.size() == 0) { - if (op == Manifold::OpType::INTERSECT) { - return Manifold::Impl(); - } - return inP_; - } - - const bool invertQ = op == Manifold::OpType::SUBTRACT; - - // Convert winding numbers to inclusion values based on operation type. - VecDH i12(x12_.size()); - VecDH i21(x21_.size()); - VecDH i03(w03_.size()); - VecDH i30(w30_.size()); - - transform(policy_, x12_.begin(), x12_.end(), i12.begin(), c3 * _1); - transform(policy_, x21_.begin(), x21_.end(), i21.begin(), c3 * _1); - transform(policy_, w03_.begin(), w03_.end(), i03.begin(), c1 + c3 * _1); - transform(policy_, w30_.begin(), w30_.end(), i30.begin(), c2 + c3 * _1); - - VecDH vP2R(inP_.NumVert()); - exclusive_scan(policy_, i03.begin(), i03.end(), vP2R.begin(), 0, AbsSum()); - int numVertR = AbsSum()(vP2R.back(), i03.back()); - const int nPv = numVertR; - - VecDH vQ2R(inQ_.NumVert()); - exclusive_scan(policy_, i30.begin(), i30.end(), vQ2R.begin(), numVertR, - AbsSum()); - numVertR = AbsSum()(vQ2R.back(), i30.back()); - const int nQv = numVertR - nPv; - - VecDH v12R(v12_.size()); - if (v12_.size() > 0) { - exclusive_scan(policy_, i12.begin(), i12.end(), v12R.begin(), numVertR, - AbsSum()); - numVertR = AbsSum()(v12R.back(), i12.back()); - } - const int n12 = numVertR - nPv - nQv; - - VecDH v21R(v21_.size()); - if (v21_.size() > 0) { - exclusive_scan(policy_, i21.begin(), i21.end(), v21R.begin(), numVertR, - AbsSum()); - numVertR = AbsSum()(v21R.back(), i21.back()); - } - const int n21 = numVertR - nPv - nQv - n12; - - // Create the output Manifold - Manifold::Impl outR; - outR.meshids = inP_.meshids + inQ_.meshids; - - if (numVertR == 0) return outR; - - outR.precision_ = glm::max(inP_.precision_, inQ_.precision_); - - outR.vertPos_.resize(numVertR); - // Add vertices, duplicating for inclusion numbers not in [-1, 1]. - // Retained vertices from P and Q: - for_each_n(policy_, zip(i03.begin(), vP2R.begin(), inP_.vertPos_.begin()), - inP_.NumVert(), DuplicateVerts({outR.vertPos_.ptrD()})); - for_each_n(policy_, zip(i30.begin(), vQ2R.begin(), inQ_.vertPos_.begin()), - inQ_.NumVert(), DuplicateVerts({outR.vertPos_.ptrD()})); - // New vertices created from intersections: - for_each_n(policy_, zip(i12.begin(), v12R.begin(), v12_.begin()), i12.size(), - DuplicateVerts({outR.vertPos_.ptrD()})); - for_each_n(policy_, zip(i21.begin(), v21R.begin(), v21_.begin()), i21.size(), - DuplicateVerts({outR.vertPos_.ptrD()})); - - PRINT(nPv << " verts from inP"); - PRINT(nQv << " verts from inQ"); - PRINT(n12 << " new verts from edgesP -> facesQ"); - PRINT(n21 << " new verts from facesP -> edgesQ"); - - // Build up new polygonal faces from triangle intersections. At this point the - // calculation switches from parallel to serial. - - // Level 3 - - // This key is the forward halfedge index of P or Q. Only includes intersected - // edges. - std::map> edgesP, edgesQ; - // This key is the face index of - std::map, std::vector> edgesNew; - - AddNewEdgeVerts(edgesP, edgesNew, p1q2_, i12, v12R, inP_.halfedge_, true); - AddNewEdgeVerts(edgesQ, edgesNew, p2q1_, i21, v21R, inQ_.halfedge_, false); - - // Level 4 - VecDH faceEdge; - VecDH facePQ2R; - std::tie(faceEdge, facePQ2R) = SizeOutput( - outR, inP_, inQ_, i03, i30, i12, i21, p1q2_, p2q1_, invertQ, policy_); - - const int numFaceR = faceEdge.size() - 1; - // This gets incremented for each halfedge that's added to a face so that the - // next one knows where to slot in. - VecDH facePtrR = faceEdge; - // Intersected halfedges are marked false. - VecDH wholeHalfedgeP(inP_.halfedge_.size(), true); - VecDH wholeHalfedgeQ(inQ_.halfedge_.size(), true); - // The halfedgeRef contains the data that will become triBary once the faces - // are triangulated. - VecDH halfedgeRef(2 * outR.NumEdge()); - - AppendPartialEdges(outR, wholeHalfedgeP, facePtrR, edgesP, halfedgeRef, inP_, - i03, vP2R, facePQ2R.begin(), true); - AppendPartialEdges(outR, wholeHalfedgeQ, facePtrR, edgesQ, halfedgeRef, inQ_, - i30, vQ2R, facePQ2R.begin() + inP_.NumTri(), false); - - AppendNewEdges(outR, facePtrR, edgesNew, halfedgeRef, facePQ2R, - inP_.NumTri()); - - AppendWholeEdges(outR, facePtrR, halfedgeRef, inP_, wholeHalfedgeP, i03, vP2R, - facePQ2R.cptrD(), true, policy_); - AppendWholeEdges(outR, facePtrR, halfedgeRef, inQ_, wholeHalfedgeQ, i30, vQ2R, - facePQ2R.cptrD() + inP_.NumTri(), false, policy_); - - VecDH faceRef; - VecDH halfedgeBary; - std::tie(faceRef, halfedgeBary) = CalculateMeshRelation( - outR, halfedgeRef, inP_, inQ_, nPv + nQv, numFaceR, invertQ, policy_); - -#ifdef MANIFOLD_DEBUG - assemble.Stop(); - Timer triangulate; - triangulate.Start(); -#endif - - // Level 6 - - if (ManifoldParams().intermediateChecks) - ASSERT(outR.IsManifold(), logicErr, "polygon mesh is not manifold!"); - - outR.Face2Tri(faceEdge, faceRef, halfedgeBary); - -#ifdef MANIFOLD_DEBUG - triangulate.Stop(); - Timer simplify; - simplify.Start(); -#endif - - if (ManifoldParams().intermediateChecks) - ASSERT(outR.IsManifold(), logicErr, "triangulated mesh is not manifold!"); - - outR.SimplifyTopology(); - - if (ManifoldParams().intermediateChecks) - ASSERT(outR.Is2Manifold(), logicErr, "simplified mesh is not 2-manifold!"); - - outR.IncrementMeshIDs(0, outR.NumTri()); - -#ifdef MANIFOLD_DEBUG - simplify.Stop(); - Timer sort; - sort.Start(); -#endif - - outR.Finish(); - -#ifdef MANIFOLD_DEBUG - sort.Stop(); - if (ManifoldParams().verbose) { - assemble.Print("Assembly"); - triangulate.Print("Triangulation"); - simplify.Print("Simplification"); - sort.Print("Sorting"); - std::cout << outR.NumVert() << " verts and " << outR.NumTri() << " tris" - << std::endl; - } -#endif - - return outR; -} - -} // namespace manifold diff --git a/IfcPlusPlus/src/external/manifold/src/manifold/src/constructors.cpp b/IfcPlusPlus/src/external/manifold/src/manifold/src/constructors.cpp deleted file mode 100644 index 34c31d213..000000000 --- a/IfcPlusPlus/src/external/manifold/src/manifold/src/constructors.cpp +++ /dev/null @@ -1,421 +0,0 @@ -// Copyright 2021 The Manifold Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -#include "csg_tree.h" -#include "graph.h" -#include "impl.h" -#include "par.h" -#include "polygon.h" - -namespace { -using namespace manifold; -using namespace thrust::placeholders; - -struct ToSphere { - float length; - __host__ __device__ void operator()(glm::vec3& v) { - v = glm::cos(glm::half_pi() * (1.0f - v)); - v = length * glm::normalize(v); - if (isnan(v.x)) v = glm::vec3(0.0); - } -}; - -struct Equals { - int val; - __host__ __device__ bool operator()(int x) { return x == val; } -}; - -struct RemoveFace { - const Halfedge* halfedge; - const int* vertLabel; - const int keepLabel; - - __host__ __device__ bool operator()(int face) { - return vertLabel[halfedge[3 * face].startVert] != keepLabel; - } -}; -} // namespace - -namespace manifold { -/** - * Constructs a smooth version of the input mesh by creating tangents; this - * method will throw if you have supplied tangents with your mesh already. The - * actual triangle resolution is unchanged; use the Refine() method to - * interpolate to a higher-resolution curve. - * - * By default, every edge is calculated for maximum smoothness (very much - * approximately), attempting to minimize the maximum mean Curvature magnitude. - * No higher-order derivatives are considered, as the interpolation is - * independent per triangle, only sharing constraints on their boundaries. - * - * @param mesh input Mesh. - * @param sharpenedEdges If desired, you can supply a vector of sharpened - * halfedges, which should in general be a small subset of all halfedges. Order - * of entries doesn't matter, as each one specifies the desired smoothness - * (between zero and one, with one the default for all unspecified halfedges) - * and the halfedge index (3 * triangle index + [0,1,2] where 0 is the edge - * between triVert 0 and 1, etc). - * - * At a smoothness value of zero, a sharp crease is made. The smoothness is - * interpolated along each edge, so the specified value should be thought of as - * an average. Where exactly two sharpened edges meet at a vertex, their - * tangents are rotated to be colinear so that the sharpened edge can be - * continuous. Vertices with only one sharpened edge are completely smooth, - * allowing sharpened edges to smoothly vanish at termination. A single vertex - * can be sharpened by sharping all edges that are incident on it, allowing - * cones to be formed. - */ -Manifold Manifold::Smooth(const Mesh& mesh, - const std::vector& sharpenedEdges) { - ASSERT(mesh.halfedgeTangent.empty(), std::runtime_error, - "when supplying tangents, the normal constructor should be used " - "rather than Smooth()."); - - std::shared_ptr impl = std::make_shared(mesh); - impl->CreateTangents(sharpenedEdges); - return Manifold(impl); -} - -/** - * Constructs a tetrahedron centered at the origin with one vertex at (1,1,1) - * and the rest at similarly symmetric points. - */ -Manifold Manifold::Tetrahedron() { - return Manifold(std::make_shared(Impl::Shape::TETRAHEDRON)); -} - -/** - * Constructs a unit cube (edge lengths all one), by default in the first - * octant, touching the origin. - * - * @param size The X, Y, and Z dimensions of the box. - * @param center Set to true to shift the center to the origin. - */ -Manifold Manifold::Cube(glm::vec3 size, bool center) { - auto cube = Manifold(std::make_shared(Impl::Shape::CUBE)); - cube = cube.Scale(size); - if (center) cube = cube.Translate(-size / 2.0f); - return cube; -} - -/** - * A convenience constructor for the common case of extruding a circle. Can also - * form cones if both radii are specified. - * - * @param height Z-extent - * @param radiusLow Radius of bottom circle. Must be positive. - * @param radiusHigh Radius of top circle. Can equal zero. Default is equal to - * radiusLow. - * @param circularSegments How many line segments to use around the circle. - * Default is calculated by the static Defaults. - * @param center Set to true to shift the center to the origin. Default is - * origin at the bottom. - */ -Manifold Manifold::Cylinder(float height, float radiusLow, float radiusHigh, - int circularSegments, bool center) { - float scale = radiusHigh >= 0.0f ? radiusHigh / radiusLow : 1.0f; - float radius = fmax(radiusLow, radiusHigh); - int n = circularSegments > 2 ? circularSegments : GetCircularSegments(radius); - Polygons circle(1); - float dPhi = 360.0f / n; - for (int i = 0; i < n; ++i) { - circle[0].push_back( - {radiusLow * glm::vec2(cosd(dPhi * i), sind(dPhi * i)), 0}); - } - Manifold cylinder = - Manifold::Extrude(circle, height, 0, 0.0f, glm::vec2(scale)); - if (center) - cylinder = cylinder.Translate(glm::vec3(0.0f, 0.0f, -height / 2.0f)); - return cylinder; -} - -/** - * Constructs a geodesic sphere of a given radius. - * - * @param radius Radius of the sphere. Must be positive. - * @param circularSegments Number of segments along its - * diameter. This number will always be rounded up to the nearest factor of - * four, as this sphere is constructed by refining an octahedron. This means - * there are a circle of vertices on all three of the axis planes. Default is - * calculated by the static Defaults. - */ -Manifold Manifold::Sphere(float radius, int circularSegments) { - int n = circularSegments > 0 ? (circularSegments + 3) / 4 - : GetCircularSegments(radius) / 4; - auto pImpl_ = std::make_shared(Impl::Shape::OCTAHEDRON); - pImpl_->Subdivide(n); - for_each_n(autoPolicy(pImpl_->NumVert()), pImpl_->vertPos_.begin(), - pImpl_->NumVert(), ToSphere({radius})); - pImpl_->Finish(); - // Ignore preceding octahedron. - pImpl_->ReinitializeReference(Impl::meshIDCounter_.fetch_add(1)); - return Manifold(pImpl_); -} - -/** - * Constructs a manifold from a set of polygons by extruding them along the - * Z-axis. - * - * @param crossSection A set of non-overlapping polygons to extrude. - * @param height Z-extent of extrusion. - * @param nDivisions Number of extra copies of the crossSection to insert into - * the shape vertically; especially useful in combination with twistDegrees to - * avoid interpolation artifacts. Default is none. - * @param twistDegrees Amount to twist the top crossSection relative to the - * bottom, interpolated linearly for the divisions in between. - * @param scaleTop Amount to scale the top (independently in X and Y). If the - * scale is {0, 0}, a pure cone is formed with only a single vertex at the top. - * Default {1, 1}. - */ -Manifold Manifold::Extrude(Polygons crossSection, float height, int nDivisions, - float twistDegrees, glm::vec2 scaleTop) { - scaleTop.x = glm::max(scaleTop.x, 0.0f); - scaleTop.y = glm::max(scaleTop.y, 0.0f); - - auto pImpl_ = std::make_shared(); - ++nDivisions; - auto& vertPos = pImpl_->vertPos_; - VecDH triVertsDH; - auto& triVerts = triVertsDH; - int nCrossSection = 0; - bool isCone = scaleTop.x == 0.0 && scaleTop.y == 0.0; - int idx = 0; - for (auto& poly : crossSection) { - nCrossSection += poly.size(); - for (PolyVert& polyVert : poly) { - vertPos.push_back({polyVert.pos.x, polyVert.pos.y, 0.0f}); - polyVert.idx = idx++; - } - } - for (int i = 1; i < nDivisions + 1; ++i) { - float alpha = i / float(nDivisions); - float phi = alpha * twistDegrees; - glm::mat2 transform(cosd(phi), sind(phi), -sind(phi), cosd(phi)); - glm::vec2 scale = glm::mix(glm::vec2(1.0f), scaleTop, alpha); - transform = transform * glm::mat2(scale.x, 0.0f, 0.0f, scale.y); - int j = 0; - int idx = 0; - for (const auto& poly : crossSection) { - for (int vert = 0; vert < poly.size(); ++vert) { - int offset = idx + nCrossSection * i; - int thisVert = vert + offset; - int lastVert = (vert == 0 ? poly.size() : vert) - 1 + offset; - if (i == nDivisions && isCone) { - triVerts.push_back({nCrossSection * i + j, lastVert - nCrossSection, - thisVert - nCrossSection}); - } else { - glm::vec2 pos = transform * poly[vert].pos; - vertPos.push_back({pos.x, pos.y, height * alpha}); - triVerts.push_back({thisVert, lastVert, thisVert - nCrossSection}); - triVerts.push_back( - {lastVert, lastVert - nCrossSection, thisVert - nCrossSection}); - } - } - ++j; - idx += poly.size(); - } - } - if (isCone) - for (int j = 0; j < crossSection.size(); ++j) // Duplicate vertex for Genus - vertPos.push_back({0.0f, 0.0f, height}); - std::vector top = Triangulate(crossSection); - for (const glm::ivec3& tri : top) { - triVerts.push_back({tri[0], tri[2], tri[1]}); - if (!isCone) triVerts.push_back(tri + nCrossSection * nDivisions); - } - - pImpl_->CreateHalfedges(triVertsDH); - pImpl_->Finish(); - pImpl_->InitializeNewReference(); - return Manifold(pImpl_); -} - -/** - * Constructs a manifold from a set of polygons by revolving this cross-section - * around its Y-axis and then setting this as the Z-axis of the resulting - * manifold. If the polygons cross the Y-axis, only the part on the positive X - * side is used. Geometrically valid input will result in geometrically valid - * output. - * - * @param crossSection A set of non-overlapping polygons to revolve. - * @param circularSegments Number of segments along its diameter. Default is - * calculated by the static Defaults. - */ -Manifold Manifold::Revolve(const Polygons& crossSection, int circularSegments) { - float radius = 0.0f; - for (const auto& poly : crossSection) { - for (const auto& vert : poly) { - radius = fmax(radius, vert.pos.x); - } - } - int nDivisions = - circularSegments > 2 ? circularSegments : GetCircularSegments(radius); - auto pImpl_ = std::make_shared(); - auto& vertPos = pImpl_->vertPos_; - VecDH triVertsDH; - auto& triVerts = triVertsDH; - float dPhi = 360.0f / nDivisions; - for (const auto& poly : crossSection) { - int start = -1; - for (int polyVert = 0; polyVert < poly.size(); ++polyVert) { - if (poly[polyVert].pos.x <= 0) { - start = polyVert; - break; - } - } - if (start == -1) { // poly all positive - for (int polyVert = 0; polyVert < poly.size(); ++polyVert) { - int startVert = vertPos.size(); - int lastStart = - startVert + - (polyVert == 0 ? nDivisions * (poly.size() - 1) : -nDivisions); - for (int slice = 0; slice < nDivisions; ++slice) { - int lastSlice = (slice == 0 ? nDivisions : slice) - 1; - float phi = slice * dPhi; - glm::vec2 pos = poly[polyVert].pos; - vertPos.push_back({pos.x * cosd(phi), pos.x * sind(phi), pos.y}); - triVerts.push_back({startVert + slice, startVert + lastSlice, - lastStart + lastSlice}); - triVerts.push_back( - {lastStart + lastSlice, lastStart + slice, startVert + slice}); - } - } - } else { // poly crosses zero - int polyVert = start; - glm::vec2 pos = poly[polyVert].pos; - do { - glm::vec2 lastPos = pos; - polyVert = (polyVert + 1) % poly.size(); - pos = poly[polyVert].pos; - if (pos.x > 0) { - if (lastPos.x <= 0) { - float a = pos.x / (pos.x - lastPos.x); - vertPos.push_back({0.0f, 0.0f, glm::mix(pos.y, lastPos.y, a)}); - } - int startVert = vertPos.size(); - for (int slice = 0; slice < nDivisions; ++slice) { - int lastSlice = (slice == 0 ? nDivisions : slice) - 1; - float phi = slice * dPhi; - glm::vec2 pos = poly[polyVert].pos; - vertPos.push_back({pos.x * cosd(phi), pos.x * sind(phi), pos.y}); - if (lastPos.x > 0) { - triVerts.push_back({startVert + slice, startVert + lastSlice, - startVert - nDivisions + lastSlice}); - triVerts.push_back({startVert - nDivisions + lastSlice, - startVert - nDivisions + slice, - startVert + slice}); - } else { - triVerts.push_back( - {startVert - 1, startVert + slice, startVert + lastSlice}); - } - } - } else if (lastPos.x > 0) { - int startVert = vertPos.size(); - float a = pos.x / (pos.x - lastPos.x); - vertPos.push_back({0.0f, 0.0f, glm::mix(pos.y, lastPos.y, a)}); - for (int slice = 0; slice < nDivisions; ++slice) { - int lastSlice = (slice == 0 ? nDivisions : slice) - 1; - triVerts.push_back({startVert, startVert - nDivisions + lastSlice, - startVert - nDivisions + slice}); - } - } - } while (polyVert != start); - } - } - - pImpl_->CreateHalfedges(triVertsDH); - pImpl_->Finish(); - pImpl_->InitializeNewReference(); - return Manifold(pImpl_); -} - -/** - * Constructs a new manifold from a vector of other manifolds. This is a purely - * topological operation, so care should be taken to avoid creating - * overlapping results. It is the inverse operation of Decompose(). - * - * @param manifolds A vector of Manifolds to lazy-union together. - */ -Manifold Manifold::Compose(const std::vector& manifolds) { - std::vector> children; - for (const auto& manifold : manifolds) { - children.push_back(manifold.pNode_->ToLeafNode()); - } - return Manifold(std::make_shared(CsgLeafNode::Compose(children))); -} - -/** - * This operation returns a vector of Manifolds that are topologically - * disconnected. If everything is connected, the vector is length one, - * containing a copy of the original. It is the inverse operation of Compose(). - */ -std::vector Manifold::Decompose() const { - Graph graph; - auto pImpl_ = GetCsgLeafNode().GetImpl(); - for (int i = 0; i < NumVert(); ++i) { - graph.add_nodes(i); - } - for (const Halfedge& halfedge : pImpl_->halfedge_) { - if (halfedge.IsForward()) - graph.add_edge(halfedge.startVert, halfedge.endVert); - } - std::vector components; - const int numLabel = ConnectedComponents(components, graph); - - if (numLabel == 1) { - std::vector meshes(1); - meshes[0] = *this; - return meshes; - } - VecDH vertLabel(components); - - std::vector meshes; - for (int i = 0; i < numLabel; ++i) { - auto impl = std::make_shared(); - // inherit original object's precision - impl->precision_ = pImpl_->precision_; - impl->vertPos_.resize(NumVert()); - VecDH vertNew2Old(NumVert()); - auto policy = autoPolicy(NumVert()); - auto start = zip(impl->vertPos_.begin(), vertNew2Old.begin()); - int nVert = - copy_if( - policy, zip(pImpl_->vertPos_.begin(), countAt(0)), - zip(pImpl_->vertPos_.end(), countAt(NumVert())), vertLabel.begin(), - zip(impl->vertPos_.begin(), vertNew2Old.begin()), Equals({i})) - - start; - impl->vertPos_.resize(nVert); - - VecDH faceNew2Old(NumTri()); - sequence(policy, faceNew2Old.begin(), faceNew2Old.end()); - - int nFace = - remove_if( - policy, faceNew2Old.begin(), faceNew2Old.end(), - RemoveFace({pImpl_->halfedge_.cptrD(), vertLabel.cptrD(), i})) - - faceNew2Old.begin(); - faceNew2Old.resize(nFace); - - impl->GatherFaces(*pImpl_, faceNew2Old); - impl->ReindexVerts(vertNew2Old, pImpl_->NumVert()); - - impl->Finish(); - - meshes.push_back(Manifold(impl)); - } - return meshes; -} -} // namespace manifold diff --git a/IfcPlusPlus/src/external/manifold/src/manifold/src/csg_tree.cpp b/IfcPlusPlus/src/external/manifold/src/manifold/src/csg_tree.cpp deleted file mode 100644 index 181f57307..000000000 --- a/IfcPlusPlus/src/external/manifold/src/manifold/src/csg_tree.cpp +++ /dev/null @@ -1,464 +0,0 @@ -// Copyright 2022 The Manifold Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "csg_tree.h" - -#include - -#include "boolean3.h" -#include "impl.h" -#include "par.h" - -namespace { -using namespace manifold; -struct Transform4x3 { - const glm::mat4x3 transform; - - __host__ __device__ glm::vec3 operator()(glm::vec3 position) { - return transform * glm::vec4(position, 1.0f); - } -}; - -struct TransformNormals { - const glm::mat3 transform; - - __host__ __device__ glm::vec3 operator()(glm::vec3 normal) { - normal = glm::normalize(transform * normal); - if (isnan(normal.x)) normal = glm::vec3(0.0f); - return normal; - } -}; - -struct UpdateTriBary { - const int nextBary; - - __host__ __device__ BaryRef operator()(BaryRef ref) { - for (int i : {0, 1, 2}) - if (ref.vertBary[i] >= 0) ref.vertBary[i] += nextBary; - return ref; - } -}; - -struct UpdateHalfedge { - const int nextVert; - const int nextEdge; - const int nextFace; - - __host__ __device__ Halfedge operator()(Halfedge edge) { - edge.startVert += nextVert; - edge.endVert += nextVert; - edge.pairedHalfedge += nextEdge; - edge.face += nextFace; - return edge; - } -}; - -struct CheckOverlap { - const Box *boxes; - const size_t i; - __host__ __device__ bool operator()(int j) { - return boxes[i].DoesOverlap(boxes[j]); - } -}; -} // namespace -namespace manifold { - -std::shared_ptr CsgNode::Translate(const glm::vec3 &t) const { - glm::mat4x3 transform(1.0f); - transform[3] += t; - return Transform(transform); -} - -std::shared_ptr CsgNode::Scale(const glm::vec3 &v) const { - glm::mat4x3 transform(1.0f); - for (int i : {0, 1, 2}) transform[i] *= v; - return Transform(transform); -} - -std::shared_ptr CsgNode::Rotate(float xDegrees, float yDegrees, - float zDegrees) const { - glm::mat3 rX(1.0f, 0.0f, 0.0f, // - 0.0f, cosd(xDegrees), sind(xDegrees), // - 0.0f, -sind(xDegrees), cosd(xDegrees)); - glm::mat3 rY(cosd(yDegrees), 0.0f, -sind(yDegrees), // - 0.0f, 1.0f, 0.0f, // - sind(yDegrees), 0.0f, cosd(yDegrees)); - glm::mat3 rZ(cosd(zDegrees), sind(zDegrees), 0.0f, // - -sind(zDegrees), cosd(zDegrees), 0.0f, // - 0.0f, 0.0f, 1.0f); - glm::mat4x3 transform(rZ * rY * rX); - return Transform(transform); -} - -CsgLeafNode::CsgLeafNode() : pImpl_(std::make_shared()) {} - -CsgLeafNode::CsgLeafNode(std::shared_ptr pImpl_) - : pImpl_(pImpl_) {} - -CsgLeafNode::CsgLeafNode(std::shared_ptr pImpl_, - glm::mat4x3 transform_) - : pImpl_(pImpl_), transform_(transform_) {} - -std::shared_ptr CsgLeafNode::GetImpl() const { - if (transform_ == glm::mat4x3(1.0f)) return pImpl_; - pImpl_ = - std::make_shared(pImpl_->Transform(transform_)); - transform_ = glm::mat4x3(1.0f); - return pImpl_; -} - -glm::mat4x3 CsgLeafNode::GetTransform() const { return transform_; } - -std::shared_ptr CsgLeafNode::ToLeafNode() const { - return std::make_shared(*this); -} - -std::shared_ptr CsgLeafNode::Transform(const glm::mat4x3 &m) const { - return std::make_shared(pImpl_, m * glm::mat4(transform_)); -} - -CsgNodeType CsgLeafNode::GetNodeType() const { return CsgNodeType::LEAF; } - -/** - * Efficient union of a set of pairwise disjoint meshes. - */ -Manifold::Impl CsgLeafNode::Compose( - const std::vector> &nodes) { - float precision = -1; - int numVert = 0; - int numEdge = 0; - int numTri = 0; - int numBary = 0; - int meshids = 0; - for (auto &node : nodes) { - meshids += node->pImpl_->meshids; - float nodeOldScale = node->pImpl_->bBox_.Scale(); - float nodeNewScale = - node->pImpl_->bBox_.Transform(node->transform_).Scale(); - float nodePrecision = node->pImpl_->precision_; - nodePrecision *= glm::max(1.0f, nodeNewScale / nodeOldScale); - nodePrecision = glm::max(nodePrecision, kTolerance * nodeNewScale); - if (!glm::isfinite(nodePrecision)) nodePrecision = -1; - precision = glm::max(precision, nodePrecision); - - numVert += node->pImpl_->NumVert(); - numEdge += node->pImpl_->NumEdge(); - numTri += node->pImpl_->NumTri(); - numBary += node->pImpl_->meshRelation_.barycentric.size(); - } - - Manifold::Impl combined; - combined.meshids = meshids; - combined.precision_ = precision; - combined.vertPos_.resize(numVert); - combined.halfedge_.resize(2 * numEdge); - combined.faceNormal_.resize(numTri); - combined.halfedgeTangent_.resize(2 * numEdge); - combined.meshRelation_.barycentric.resize(numBary); - combined.meshRelation_.triBary.resize(numTri); - auto policy = autoPolicy(numTri); - - int nextVert = 0; - int nextEdge = 0; - int nextTri = 0; - int nextBary = 0; - for (auto &node : nodes) { - if (node->transform_ == glm::mat4x3(1.0f)) { - copy(policy, node->pImpl_->vertPos_.begin(), node->pImpl_->vertPos_.end(), - combined.vertPos_.begin() + nextVert); - copy(policy, node->pImpl_->faceNormal_.begin(), - node->pImpl_->faceNormal_.end(), - combined.faceNormal_.begin() + nextTri); - } else { - // no need to apply the transform to the node, just copy the vertices and - // face normals and apply transform on the fly - auto vertPosBegin = thrust::make_transform_iterator( - node->pImpl_->vertPos_.begin(), Transform4x3({node->transform_})); - glm::mat3 normalTransform = - glm::inverse(glm::transpose(glm::mat3(node->transform_))); - auto faceNormalBegin = - thrust::make_transform_iterator(node->pImpl_->faceNormal_.begin(), - TransformNormals({normalTransform})); - copy_n(policy, vertPosBegin, node->pImpl_->vertPos_.size(), - combined.vertPos_.begin() + nextVert); - copy_n(policy, faceNormalBegin, node->pImpl_->faceNormal_.size(), - combined.faceNormal_.begin() + nextTri); - } - copy(policy, node->pImpl_->halfedgeTangent_.begin(), - node->pImpl_->halfedgeTangent_.end(), - combined.halfedgeTangent_.begin() + nextEdge); - copy(policy, node->pImpl_->meshRelation_.barycentric.begin(), - node->pImpl_->meshRelation_.barycentric.end(), - combined.meshRelation_.barycentric.begin() + nextBary); - transform(policy, node->pImpl_->meshRelation_.triBary.begin(), - node->pImpl_->meshRelation_.triBary.end(), - combined.meshRelation_.triBary.begin() + nextTri, - UpdateTriBary({nextBary})); - transform(policy, node->pImpl_->halfedge_.begin(), - node->pImpl_->halfedge_.end(), - combined.halfedge_.begin() + nextEdge, - UpdateHalfedge({nextVert, nextEdge, nextTri})); - - // Since the nodes may be copies containing the same meshIDs, it is - // important to increment them separately so that each node instance gets - // unique meshIDs. - combined.IncrementMeshIDs(nextTri, node->pImpl_->NumTri()); - - nextVert += node->pImpl_->NumVert(); - nextEdge += 2 * node->pImpl_->NumEdge(); - nextTri += node->pImpl_->NumTri(); - nextBary += node->pImpl_->meshRelation_.barycentric.size(); - } - // required to remove parts that are smaller than the precision - combined.SimplifyTopology(); - combined.Finish(); - return combined; -} - -CsgOpNode::CsgOpNode() {} - -CsgOpNode::CsgOpNode(const std::vector> &children, - Manifold::OpType op) - : impl_(std::make_shared()) { - impl_->children_ = children; - SetOp(op); - // opportunistically flatten the tree without costly evaluation - GetChildren(false); -} - -CsgOpNode::CsgOpNode(std::vector> &&children, - Manifold::OpType op) - : impl_(std::make_shared()) { - impl_->children_ = children; - SetOp(op); - // opportunistically flatten the tree without costly evaluation - GetChildren(false); -} - -std::shared_ptr CsgOpNode::Transform(const glm::mat4x3 &m) const { - auto node = std::make_shared(); - node->impl_ = impl_; - node->transform_ = m * glm::mat4(transform_); - return node; -} - -std::shared_ptr CsgOpNode::ToLeafNode() const { - if (cache_ != nullptr) return cache_; - if (impl_->children_.empty()) return nullptr; - // turn the children into leaf nodes - GetChildren(); - auto &children_ = impl_->children_; - if (children_.size() > 1) { - switch (impl_->op_) { - case CsgNodeType::UNION: - BatchUnion(); - break; - case CsgNodeType::INTERSECTION: { - std::vector> impls; - for (auto &child : children_) { - impls.push_back( - std::dynamic_pointer_cast(child)->GetImpl()); - } - BatchBoolean(Manifold::OpType::INTERSECT, impls); - children_.clear(); - children_.push_back(std::make_shared(impls.front())); - break; - }; - case CsgNodeType::DIFFERENCE: { - // take the lhs out and treat the remaining nodes as the rhs, perform - // union optimization for them - auto lhs = std::dynamic_pointer_cast(children_.front()); - children_.erase(children_.begin()); - BatchUnion(); - auto rhs = std::dynamic_pointer_cast(children_.front()); - children_.clear(); - Boolean3 boolean(*lhs->GetImpl(), *rhs->GetImpl(), - Manifold::OpType::SUBTRACT); - children_.push_back( - std::make_shared(std::make_shared( - boolean.Result(Manifold::OpType::SUBTRACT)))); - }; - case CsgNodeType::LEAF: - // unreachable - break; - } - } - // children_ must contain only one CsgLeafNode now, and its Transform will - // give CsgLeafNode as well - cache_ = std::dynamic_pointer_cast( - children_.front()->Transform(transform_)); - return cache_; -} - -/** - * Efficient boolean operation on a set of nodes utilizing commutativity of the - * operation. Only supports union and intersection. - */ -void CsgOpNode::BatchBoolean( - Manifold::OpType operation, - std::vector> &results) { - ASSERT(operation != Manifold::OpType::SUBTRACT, logicErr, - "BatchBoolean doesn't support Difference."); - auto cmpFn = [](std::shared_ptr a, - std::shared_ptr b) { - // invert the order because we want a min heap - return a->NumVert() > b->NumVert(); - }; - - // apply boolean operations starting from smaller meshes - // the assumption is that boolean operations on smaller meshes is faster, - // due to less data being copied and processed - std::make_heap(results.begin(), results.end(), cmpFn); - while (results.size() > 1) { - std::pop_heap(results.begin(), results.end(), cmpFn); - auto a = std::move(results.back()); - results.pop_back(); - std::pop_heap(results.begin(), results.end(), cmpFn); - auto b = std::move(results.back()); - results.pop_back(); - // boolean operation - Boolean3 boolean(*a, *b, operation); - results.push_back( - std::make_shared(boolean.Result(operation))); - std::push_heap(results.begin(), results.end(), cmpFn); - } -} - -/** - * Efficient union operation on a set of nodes by doing Compose as much as - * possible. - * Note: Due to some unknown issues with `Compose`, we are now doing - * `BatchBoolean` instead of using `Compose` for non-intersecting manifolds. - */ -void CsgOpNode::BatchUnion() const { - // INVARIANT: children_ is a vector of leaf nodes - // this kMaxUnionSize is a heuristic to avoid the pairwise disjoint check - // with O(n^2) complexity to take too long. - // If the number of children exceeded this limit, we will operate on chunks - // with size kMaxUnionSize. - constexpr int kMaxUnionSize = 1000; - auto &children_ = impl_->children_; - while (children_.size() > 1) { - const int start = (children_.size() > kMaxUnionSize) - ? (children_.size() - kMaxUnionSize) - : 0; - VecDH boxes; - boxes.reserve(children_.size() - start); - for (int i = start; i < children_.size(); i++) { - boxes.push_back(std::dynamic_pointer_cast(children_[i]) - ->GetImpl() - ->bBox_); - } - const Box *boxesD = boxes.cptrD(); - // partition the children into a set of disjoint sets - // each set contains a set of children that are pairwise disjoint - std::vector> disjointSets; - for (size_t i = 0; i < boxes.size(); i++) { - auto lambda = [boxesD, i](const VecDH &set) { - return find_if( - autoPolicy(set.size()), set.begin(), set.end(), - CheckOverlap({boxesD, i})) == set.end(); - }; - auto it = std::find_if(disjointSets.begin(), disjointSets.end(), lambda); - if (it == disjointSets.end()) { - disjointSets.push_back(std::vector{i}); - } else { - it->push_back(i); - } - } - // compose each set of disjoint children - std::vector> impls; - for (const auto &set : disjointSets) { - if (set.size() == 1) { - impls.push_back( - std::dynamic_pointer_cast(children_[start + set[0]]) - ->GetImpl()); - } else { - std::vector> tmp; - for (size_t j : set) { - tmp.push_back( - std::dynamic_pointer_cast(children_[start + j])); - } - impls.push_back( - std::make_shared(CsgLeafNode::Compose(tmp))); - } - } - BatchBoolean(Manifold::OpType::ADD, impls); - children_.erase(children_.begin() + start, children_.end()); - children_.push_back(std::make_shared(impls.back())); - // move it to the front as we process from the back, and the newly added - // child should be quite complicated - std::swap(children_.front(), children_.back()); - } -} - -/** - * Flatten the children to a list of leaf nodes and return them. - * If finalize is true, the list will be guaranteed to be a list of leaf nodes - * (i.e. no ops). Otherwise, the list may contain ops. - * Note that this function will not apply the transform to children, as they may - * be shared with other nodes. - */ -std::vector> &CsgOpNode::GetChildren( - bool finalize) const { - auto &children_ = impl_->children_; - if (children_.empty() || (impl_->simplified_ && !finalize) || - impl_->flattened_) - return children_; - impl_->simplified_ = true; - impl_->flattened_ = finalize; - std::vector> newChildren; - - CsgNodeType op = impl_->op_; - for (auto &child : children_) { - if (child->GetNodeType() == op && child.use_count() == 1 && - std::dynamic_pointer_cast(child)->impl_.use_count() == 1) { - auto grandchildren = - std::dynamic_pointer_cast(child)->GetChildren(finalize); - int start = children_.size(); - for (auto &grandchild : grandchildren) { - newChildren.push_back(grandchild->Transform(child->GetTransform())); - } - } else { - if (!finalize || child->GetNodeType() == CsgNodeType::LEAF) { - newChildren.push_back(child); - } else { - newChildren.push_back(child->ToLeafNode()); - } - } - // special handling for difference: we treat it as first - (second + third + - // ...) so op = UNION after the first node - if (op == CsgNodeType::DIFFERENCE) op = CsgNodeType::UNION; - } - children_ = newChildren; - return children_; -} - -void CsgOpNode::SetOp(Manifold::OpType op) { - switch (op) { - case Manifold::OpType::ADD: - impl_->op_ = CsgNodeType::UNION; - break; - case Manifold::OpType::SUBTRACT: - impl_->op_ = CsgNodeType::DIFFERENCE; - break; - case Manifold::OpType::INTERSECT: - impl_->op_ = CsgNodeType::INTERSECTION; - break; - } -} - -glm::mat4x3 CsgOpNode::GetTransform() const { return transform_; } - -} // namespace manifold diff --git a/IfcPlusPlus/src/external/manifold/src/manifold/src/csg_tree.h b/IfcPlusPlus/src/external/manifold/src/manifold/src/csg_tree.h deleted file mode 100644 index d9cabccbf..000000000 --- a/IfcPlusPlus/src/external/manifold/src/manifold/src/csg_tree.h +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright 2022 The Manifold Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once -#include "manifold.h" - -namespace manifold { - -enum class CsgNodeType { UNION, INTERSECTION, DIFFERENCE, LEAF }; - -class CsgLeafNode; - -class CsgNode { - public: - virtual std::shared_ptr ToLeafNode() const = 0; - virtual std::shared_ptr Transform(const glm::mat4x3 &m) const = 0; - virtual CsgNodeType GetNodeType() const = 0; - virtual glm::mat4x3 GetTransform() const = 0; - - std::shared_ptr Translate(const glm::vec3 &t) const; - std::shared_ptr Scale(const glm::vec3 &s) const; - std::shared_ptr Rotate(float xDegrees = 0, float yDegrees = 0, - float zDegrees = 0) const; -}; - -class CsgLeafNode final : public CsgNode { - public: - CsgLeafNode(); - CsgLeafNode(std::shared_ptr pImpl_); - CsgLeafNode(std::shared_ptr pImpl_, - glm::mat4x3 transform_); - - std::shared_ptr GetImpl() const; - - std::shared_ptr ToLeafNode() const override; - - std::shared_ptr Transform(const glm::mat4x3 &m) const override; - - CsgNodeType GetNodeType() const override; - - glm::mat4x3 GetTransform() const override; - - static Manifold::Impl Compose( - const std::vector> &nodes); - - private: - mutable std::shared_ptr pImpl_; - mutable glm::mat4x3 transform_ = glm::mat4x3(1.0f); -}; - -class CsgOpNode final : public CsgNode { - public: - CsgOpNode(); - - CsgOpNode(const std::vector> &children, - Manifold::OpType op); - - CsgOpNode(std::vector> &&children, - Manifold::OpType op); - - std::shared_ptr Transform(const glm::mat4x3 &m) const override; - - std::shared_ptr ToLeafNode() const override; - - CsgNodeType GetNodeType() const override { return impl_->op_; } - - glm::mat4x3 GetTransform() const override; - - private: - struct Impl { - CsgNodeType op_; - mutable std::vector> children_; - mutable bool simplified_ = false; - mutable bool flattened_ = false; - }; - std::shared_ptr impl_ = nullptr; - glm::mat4x3 transform_ = glm::mat4x3(1.0f); - // the following fields are for lazy evaluation, so they are mutable - mutable std::shared_ptr cache_ = nullptr; - - void SetOp(Manifold::OpType); - - static void BatchBoolean( - Manifold::OpType operation, - std::vector> &results); - - void BatchUnion() const; - - std::vector> &GetChildren( - bool finalize = true) const; -}; - -} // namespace manifold diff --git a/IfcPlusPlus/src/external/manifold/src/manifold/src/edge_op.cpp b/IfcPlusPlus/src/external/manifold/src/manifold/src/edge_op.cpp deleted file mode 100644 index 911006bb7..000000000 --- a/IfcPlusPlus/src/external/manifold/src/manifold/src/edge_op.cpp +++ /dev/null @@ -1,490 +0,0 @@ -// Copyright 2021 The Manifold Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "impl.h" -#include "par.h" - -namespace { -using namespace manifold; - -__host__ __device__ glm::ivec3 TriOf(int edge) { - glm::ivec3 triEdge; - triEdge[0] = edge; - triEdge[1] = NextHalfedge(triEdge[0]); - triEdge[2] = NextHalfedge(triEdge[1]); - return triEdge; -} - -__host__ __device__ bool Is01Longest(glm::vec2 v0, glm::vec2 v1, glm::vec2 v2) { - const glm::vec2 e[3] = {v1 - v0, v2 - v1, v0 - v2}; - float l[3]; - for (int i : {0, 1, 2}) l[i] = glm::dot(e[i], e[i]); - return l[0] > l[1] && l[0] > l[2]; -} - -struct DuplicateEdge { - const Halfedge* sortedHalfedge; - - __host__ __device__ bool operator()(int edge) { - const Halfedge& halfedge = sortedHalfedge[edge]; - const Halfedge& nextHalfedge = sortedHalfedge[edge + 1]; - return halfedge.startVert == nextHalfedge.startVert && - halfedge.endVert == nextHalfedge.endVert; - } -}; - -struct ShortEdge { - const Halfedge* halfedge; - const glm::vec3* vertPos; - const float precision; - - __host__ __device__ bool operator()(int edge) { - if (halfedge[edge].pairedHalfedge < 0) return false; - // Flag short edges - const glm::vec3 delta = - vertPos[halfedge[edge].endVert] - vertPos[halfedge[edge].startVert]; - return glm::dot(delta, delta) < precision * precision; - } -}; - -struct FlagEdge { - const Halfedge* halfedge; - const BaryRef* triBary; - - __host__ __device__ bool operator()(int edge) { - if (halfedge[edge].pairedHalfedge < 0) return false; - // Flag redundant edges - those where the startVert is surrounded by only - // two original triangles. - const BaryRef ref0 = triBary[edge / 3]; - int current = NextHalfedge(halfedge[edge].pairedHalfedge); - const BaryRef ref1 = triBary[current / 3]; - while (current != edge) { - current = NextHalfedge(halfedge[current].pairedHalfedge); - int tri = current / 3; - const BaryRef ref = triBary[tri]; - if ((ref.meshID != ref0.meshID || ref.tri != ref0.tri) && - (ref.meshID != ref1.meshID || ref.tri != ref1.tri)) - return false; - } - return true; - } -}; - -struct SwappableEdge { - const Halfedge* halfedge; - const glm::vec3* vertPos; - const glm::vec3* triNormal; - const float precision; - - __host__ __device__ bool operator()(int edge) { - if (halfedge[edge].pairedHalfedge < 0) return false; - - int tri = halfedge[edge].face; - glm::ivec3 triedge = TriOf(edge); - glm::mat3x2 projection = GetAxisAlignedProjection(triNormal[tri]); - glm::vec2 v[3]; - for (int i : {0, 1, 2}) - v[i] = projection * vertPos[halfedge[triedge[i]].startVert]; - if (CCW(v[0], v[1], v[2], precision) > 0 || !Is01Longest(v[0], v[1], v[2])) - return false; - - // Switch to neighbor's projection. - edge = halfedge[edge].pairedHalfedge; - tri = halfedge[edge].face; - triedge = TriOf(edge); - projection = GetAxisAlignedProjection(triNormal[tri]); - for (int i : {0, 1, 2}) - v[i] = projection * vertPos[halfedge[triedge[i]].startVert]; - return CCW(v[0], v[1], v[2], precision) > 0 || - Is01Longest(v[0], v[1], v[2]); - } -}; -} // namespace - -namespace manifold { - -/** - * Collapses degenerate triangles by removing edges shorter than precision_ and - * any edge that is preceeded by an edge that joins the same two face relations. - * It also performs edge swaps on the long edges of degenerate triangles, though - * there are some configurations of degenerates that cannot be removed this way. - * - * Before collapsing edges, the mesh is checked for duplicate edges (more than - * one pair of triangles sharing the same edge), which are removed by - * duplicating one vert and adding two triangles. These degenerate triangles are - * likely to be collapsed again in the subsequent simplification. - * - * Note when an edge collapse would result in something non-manifold, the - * vertices are duplicated in such a way as to remove handles or separate - * meshes, thus decreasing the Genus(). It only increases when meshes that have - * collapsed to just a pair of triangles are removed entirely. - * - * Rather than actually removing the edges, this step merely marks them for - * removal, by setting vertPos to NaN and halfedge to {-1, -1, -1, -1}. - */ -void Manifold::Impl::SimplifyTopology() { - if (!halfedge_.size()) return; - - auto policy = autoPolicy(halfedge_.size()); - - VecDH halfedge(halfedge_); - VecDH idx(halfedge_.size()); - sequence(policy, idx.begin(), idx.end()); - sort_by_key(policy, halfedge.begin(), halfedge.end(), idx.begin()); - - VecDH flaggedEdges(halfedge_.size()); - - int numFlagged = - copy_if( - policy, idx.begin(), idx.end() - 1, countAt(0), flaggedEdges.begin(), - DuplicateEdge({halfedge.cptrD()})) - - flaggedEdges.begin(); - flaggedEdges.resize(numFlagged); - - for (const int edge : flaggedEdges) DedupeEdge(edge); - - flaggedEdges.resize(halfedge_.size()); - numFlagged = - copy_if( - policy, countAt(0), countAt(halfedge_.size()), flaggedEdges.begin(), - ShortEdge({halfedge_.cptrD(), vertPos_.cptrD(), precision_})) - - flaggedEdges.begin(); - flaggedEdges.resize(numFlagged); - - for (const int edge : flaggedEdges) CollapseEdge(edge); - - flaggedEdges.resize(halfedge_.size()); - numFlagged = - copy_if( - policy, countAt(0), countAt(halfedge_.size()), flaggedEdges.begin(), - FlagEdge({halfedge_.cptrD(), meshRelation_.triBary.cptrD()})) - - flaggedEdges.begin(); - flaggedEdges.resize(numFlagged); - - for (const int edge : flaggedEdges) CollapseEdge(edge); - - flaggedEdges.resize(halfedge_.size()); - numFlagged = - copy_if( - policy, countAt(0), countAt(halfedge_.size()), flaggedEdges.begin(), - SwappableEdge({halfedge_.cptrD(), vertPos_.cptrD(), - faceNormal_.cptrD(), precision_})) - - flaggedEdges.begin(); - flaggedEdges.resize(numFlagged); - - for (const int edge : flaggedEdges) { - RecursiveEdgeSwap(edge); - } -} - -void Manifold::Impl::DedupeEdge(const int edge) { - // Orbit endVert - const int startVert = halfedge_[edge].startVert; - const int endVert = halfedge_[edge].endVert; - int current = halfedge_[NextHalfedge(edge)].pairedHalfedge; - while (current != edge) { - const int vert = halfedge_[current].startVert; - if (vert == startVert) { - const int newVert = vertPos_.size(); - vertPos_.push_back(vertPos_[endVert]); - if (vertNormal_.size() > 0) vertNormal_.push_back(vertNormal_[endVert]); - current = halfedge_[NextHalfedge(current)].pairedHalfedge; - const int opposite = halfedge_[NextHalfedge(edge)].pairedHalfedge; - - UpdateVert(newVert, current, opposite); - - int newHalfedge = halfedge_.size(); - int newFace = newHalfedge / 3; - int oldFace = halfedge_[current].face; - int outsideVert = halfedge_[current].startVert; - halfedge_.push_back({endVert, newVert, -1, newFace}); - halfedge_.push_back({newVert, outsideVert, -1, newFace}); - halfedge_.push_back({outsideVert, endVert, -1, newFace}); - PairUp(newHalfedge + 2, halfedge_[current].pairedHalfedge); - PairUp(newHalfedge + 1, current); - if (meshRelation_.triBary.size() > 0) - meshRelation_.triBary.push_back(meshRelation_.triBary[oldFace]); - if (faceNormal_.size() > 0) faceNormal_.push_back(faceNormal_[oldFace]); - - newHalfedge += 3; - ++newFace; - oldFace = halfedge_[opposite].face; - outsideVert = halfedge_[opposite].startVert; - halfedge_.push_back({newVert, endVert, -1, newFace}); - halfedge_.push_back({endVert, outsideVert, -1, newFace}); - halfedge_.push_back({outsideVert, newVert, -1, newFace}); - PairUp(newHalfedge + 2, halfedge_[opposite].pairedHalfedge); - PairUp(newHalfedge + 1, opposite); - PairUp(newHalfedge, newHalfedge - 3); - if (meshRelation_.triBary.size() > 0) - meshRelation_.triBary.push_back(meshRelation_.triBary[oldFace]); - if (faceNormal_.size() > 0) faceNormal_.push_back(faceNormal_[oldFace]); - - break; - } - - current = halfedge_[NextHalfedge(current)].pairedHalfedge; - } -} - -void Manifold::Impl::PairUp(int edge0, int edge1) { - halfedge_[edge0].pairedHalfedge = edge1; - halfedge_[edge1].pairedHalfedge = edge0; -} - -// Traverses CW around startEdge.endVert from startEdge to endEdge -// (edgeEdge.endVert must == startEdge.endVert), updating each edge to point -// to vert instead. -void Manifold::Impl::UpdateVert(int vert, int startEdge, int endEdge) { - while (startEdge != endEdge) { - halfedge_[startEdge].endVert = vert; - startEdge = NextHalfedge(startEdge); - halfedge_[startEdge].startVert = vert; - startEdge = halfedge_[startEdge].pairedHalfedge; - } -} - -// In the event that the edge collapse would create a non-manifold edge, -// instead we duplicate the two verts and attach the manifolds the other way -// across this edge. -void Manifold::Impl::FormLoop(int current, int end) { - int startVert = vertPos_.size(); - vertPos_.push_back(vertPos_[halfedge_[current].startVert]); - int endVert = vertPos_.size(); - vertPos_.push_back(vertPos_[halfedge_[current].endVert]); - - int oldMatch = halfedge_[current].pairedHalfedge; - int newMatch = halfedge_[end].pairedHalfedge; - - UpdateVert(startVert, oldMatch, newMatch); - UpdateVert(endVert, end, current); - - halfedge_[current].pairedHalfedge = newMatch; - halfedge_[newMatch].pairedHalfedge = current; - halfedge_[end].pairedHalfedge = oldMatch; - halfedge_[oldMatch].pairedHalfedge = end; - - RemoveIfFolded(end); -} - -void Manifold::Impl::CollapseTri(const glm::ivec3& triEdge) { - int pair1 = halfedge_[triEdge[1]].pairedHalfedge; - int pair2 = halfedge_[triEdge[2]].pairedHalfedge; - halfedge_[pair1].pairedHalfedge = pair2; - halfedge_[pair2].pairedHalfedge = pair1; - for (int i : {0, 1, 2}) { - halfedge_[triEdge[i]] = {-1, -1, -1, -1}; - } -} - -void Manifold::Impl::RemoveIfFolded(int edge) { - const glm::ivec3 tri0edge = TriOf(edge); - const glm::ivec3 tri1edge = TriOf(halfedge_[edge].pairedHalfedge); - if (halfedge_[tri0edge[1]].endVert == halfedge_[tri1edge[1]].endVert) { - for (int i : {0, 1, 2}) { - vertPos_[halfedge_[tri0edge[i]].startVert] = glm::vec3(NAN); - halfedge_[tri0edge[i]] = {-1, -1, -1, -1}; - halfedge_[tri1edge[i]] = {-1, -1, -1, -1}; - } - } -} - -void Manifold::Impl::CollapseEdge(const int edge) { - VecDH& triBary = meshRelation_.triBary; - - const Halfedge toRemove = halfedge_[edge]; - if (toRemove.pairedHalfedge < 0) return; - - const int endVert = toRemove.endVert; - const glm::ivec3 tri0edge = TriOf(edge); - const glm::ivec3 tri1edge = TriOf(toRemove.pairedHalfedge); - - const glm::vec3 pNew = vertPos_[endVert]; - const glm::vec3 pOld = vertPos_[toRemove.startVert]; - const glm::vec3 delta = pNew - pOld; - const bool shortEdge = glm::dot(delta, delta) < precision_ * precision_; - - std::vector edges; - // Orbit endVert - int current = halfedge_[tri0edge[1]].pairedHalfedge; - while (current != tri1edge[2]) { - current = NextHalfedge(current); - edges.push_back(current); - current = halfedge_[current].pairedHalfedge; - } - - // Orbit startVert - int start = halfedge_[tri1edge[1]].pairedHalfedge; - const BaryRef ref0 = triBary[edge / 3]; - const BaryRef ref1 = triBary[toRemove.pairedHalfedge / 3]; - if (!shortEdge) { - current = start; - glm::vec3 pLast = vertPos_[halfedge_[tri1edge[1]].endVert]; - while (current != tri0edge[2]) { - current = NextHalfedge(current); - glm::vec3 pNext = vertPos_[halfedge_[current].endVert]; - const int tri = current / 3; - const BaryRef ref = triBary[tri]; - // Don't collapse if the edge is not redundant (this may have changed due - // to the collapse of neighbors). - if ((ref.meshID != ref0.meshID || ref.tri != ref0.tri) && - (ref.meshID != ref1.meshID || ref.tri != ref1.tri)) - return; - - // Don't collapse edge if it would cause a triangle to invert. - const glm::mat3x2 projection = GetAxisAlignedProjection(faceNormal_[tri]); - if (CCW(projection * pNext, projection * pLast, projection * pNew, - precision_) < 0) - return; - - pLast = pNext; - current = halfedge_[current].pairedHalfedge; - } - } - - // Remove toRemove.startVert and replace with endVert. - vertPos_[toRemove.startVert] = glm::vec3(NAN); - CollapseTri(tri1edge); - - // Orbit startVert - current = start; - while (current != tri0edge[2]) { - current = NextHalfedge(current); - - if (!shortEdge) { - // Update the shifted triangles to the vertBary of endVert - const int tri = current / 3; - const int vIdx = current - 3 * tri; - triBary[tri].vertBary[vIdx] = - (ref0.meshID == triBary[tri].meshID && ref0.tri == triBary[tri].tri) - ? ref0.vertBary[(edge + 1) % 3] - : ref1.vertBary[toRemove.pairedHalfedge % 3]; - } - - const int vert = halfedge_[current].endVert; - const int next = halfedge_[current].pairedHalfedge; - for (int i = 0; i < edges.size(); ++i) { - if (vert == halfedge_[edges[i]].endVert) { - FormLoop(edges[i], current); - start = next; - edges.resize(i); - break; - } - } - current = next; - } - - UpdateVert(endVert, start, tri0edge[2]); - CollapseTri(tri0edge); - RemoveIfFolded(start); -} - -void Manifold::Impl::RecursiveEdgeSwap(const int edge) { - VecDH& triBary = meshRelation_.triBary; - - if (edge < 0) return; - const int pair = halfedge_[edge].pairedHalfedge; - if (pair < 0) return; - - const glm::ivec3 tri0edge = TriOf(edge); - const glm::ivec3 tri1edge = TriOf(pair); - const glm::ivec3 perm0 = TriOf(edge % 3); - const glm::ivec3 perm1 = TriOf(pair % 3); - - glm::mat3x2 projection = GetAxisAlignedProjection(faceNormal_[edge / 3]); - glm::vec2 v[4]; - for (int i : {0, 1, 2}) - v[i] = projection * vertPos_[halfedge_[tri0edge[i]].startVert]; - // Only operate on the long edge of a degenerate triangle. - if (CCW(v[0], v[1], v[2], precision_) > 0 || !Is01Longest(v[0], v[1], v[2])) - return; - - // Switch to neighbor's projection. - projection = GetAxisAlignedProjection(faceNormal_[halfedge_[pair].face]); - for (int i : {0, 1, 2}) - v[i] = projection * vertPos_[halfedge_[tri0edge[i]].startVert]; - v[3] = projection * vertPos_[halfedge_[tri1edge[2]].startVert]; - - auto SwapEdge = [&]() { - // The 0-verts are swapped to the opposite 2-verts. - const int v0 = halfedge_[tri0edge[2]].startVert; - const int v1 = halfedge_[tri1edge[2]].startVert; - halfedge_[tri0edge[0]].startVert = v1; - halfedge_[tri0edge[2]].endVert = v1; - halfedge_[tri1edge[0]].startVert = v0; - halfedge_[tri1edge[2]].endVert = v0; - PairUp(tri0edge[0], halfedge_[tri1edge[2]].pairedHalfedge); - PairUp(tri1edge[0], halfedge_[tri0edge[2]].pairedHalfedge); - PairUp(tri0edge[2], tri1edge[2]); - // Both triangles are now subsets of the neighboring triangle. - const int tri0 = halfedge_[tri0edge[0]].face; - const int tri1 = halfedge_[tri1edge[0]].face; - faceNormal_[tri0] = faceNormal_[tri1]; - triBary[tri0] = triBary[tri1]; - triBary[tri0].vertBary[perm0[1]] = triBary[tri1].vertBary[perm1[0]]; - triBary[tri0].vertBary[perm0[0]] = triBary[tri1].vertBary[perm1[2]]; - // Calculate a new barycentric coordinate for the split triangle. - const glm::vec3 uvw0 = UVW(triBary[tri1].vertBary[perm1[0]], - meshRelation_.barycentric.cptrH()); - const glm::vec3 uvw1 = UVW(triBary[tri1].vertBary[perm1[1]], - meshRelation_.barycentric.cptrH()); - const float l01 = glm::length(v[1] - v[0]); - const float l02 = glm::length(v[2] - v[0]); - const float a = glm::max(0.0f, glm::min(1.0f, l02 / l01)); - const glm::vec3 uvw2 = a * uvw0 + (1 - a) * uvw1; - // And assign it. - const int newBary = meshRelation_.barycentric.size(); - meshRelation_.barycentric.push_back(uvw2); - triBary[tri1].vertBary[perm1[0]] = newBary; - triBary[tri0].vertBary[perm0[2]] = newBary; - - // if the new edge already exists, duplicate the verts and split the mesh. - int current = halfedge_[tri1edge[0]].pairedHalfedge; - const int endVert = halfedge_[tri1edge[1]].endVert; - while (current != tri0edge[1]) { - current = NextHalfedge(current); - if (halfedge_[current].endVert == endVert) { - FormLoop(tri0edge[2], current); - RemoveIfFolded(tri0edge[2]); - return; - } - current = halfedge_[current].pairedHalfedge; - } - }; - - // Only operate if the other triangles are not degenerate. - if (CCW(v[1], v[0], v[3], precision_) <= 0) { - if (!Is01Longest(v[1], v[0], v[3])) return; - // Two facing, long-edge degenerates can swap. - SwapEdge(); - const glm::vec2 e23 = v[3] - v[2]; - if (glm::dot(e23, e23) < precision_ * precision_) { - CollapseEdge(tri0edge[2]); - } else { - RecursiveEdgeSwap(tri0edge[0]); - RecursiveEdgeSwap(tri0edge[1]); - RecursiveEdgeSwap(tri1edge[0]); - RecursiveEdgeSwap(tri1edge[1]); - } - return; - } else if (CCW(v[0], v[3], v[2], precision_) <= 0 || - CCW(v[1], v[2], v[3], precision_) <= 0) { - return; - } - // Normal path - SwapEdge(); - RecursiveEdgeSwap(halfedge_[tri0edge[1]].pairedHalfedge); - RecursiveEdgeSwap(halfedge_[tri1edge[0]].pairedHalfedge); -} -} // namespace manifold diff --git a/IfcPlusPlus/src/external/manifold/src/manifold/src/face_op.cpp b/IfcPlusPlus/src/external/manifold/src/manifold/src/face_op.cpp deleted file mode 100644 index 2494d9047..000000000 --- a/IfcPlusPlus/src/external/manifold/src/manifold/src/face_op.cpp +++ /dev/null @@ -1,195 +0,0 @@ -// Copyright 2021 The Manifold Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -#include "impl.h" -#include "polygon.h" - -namespace manifold { - -/** - * Triangulates the faces. In this case, the halfedge_ vector is not yet a set - * of triangles as required by this data structure, but is instead a set of - * general faces with the input faceEdge vector having length of the number of - * faces + 1. The values are indicies into the halfedge_ vector for the first - * edge of each face, with the final value being the length of the halfedge_ - * vector itself. Upon return, halfedge_ has been lengthened and properly - * represents the mesh as a set of triangles as usual. In this process the - * faceNormal_ values are retained, repeated as necessary. - */ -void Manifold::Impl::Face2Tri(const VecDH& faceEdge, - const VecDH& faceRef, - const VecDH& halfedgeBary) { - VecDH triVerts; - VecDH triNormal; - VecDH& triBary = meshRelation_.triBary; - triBary.resize(0); - triVerts.reserve(halfedge_.size()); - triNormal.reserve(halfedge_.size()); - triBary.reserve(halfedge_.size()); - - for (int face = 0; face < faceEdge.size() - 1; ++face) { - const int firstEdge = faceEdge[face]; - const int lastEdge = faceEdge[face + 1]; - const int numEdge = lastEdge - firstEdge; - ASSERT(numEdge >= 3, topologyErr, "face has less than three edges."); - const glm::vec3 normal = faceNormal_[face]; - - auto linearSearch = [](const int* mapping, int value) { - int i = 0; - while (mapping[i] != value) ++i; - return i; - }; - - if (numEdge == 3) { // Single triangle - int mapping[3] = {halfedge_[firstEdge].startVert, - halfedge_[firstEdge + 1].startVert, - halfedge_[firstEdge + 2].startVert}; - glm::ivec3 tri(halfedge_[firstEdge].startVert, - halfedge_[firstEdge + 1].startVert, - halfedge_[firstEdge + 2].startVert); - glm::ivec3 ends(halfedge_[firstEdge].endVert, - halfedge_[firstEdge + 1].endVert, - halfedge_[firstEdge + 2].endVert); - if (ends[0] == tri[2]) { - std::swap(tri[1], tri[2]); - std::swap(ends[1], ends[2]); - } - ASSERT(ends[0] == tri[1] && ends[1] == tri[2] && ends[2] == tri[0], - topologyErr, "These 3 edges do not form a triangle!"); - - triVerts.push_back(tri); - triNormal.push_back(normal); - triBary.push_back(faceRef[face]); - for (int k : {0, 1, 2}) { - int index = linearSearch(mapping, tri[k]); - triBary.back().vertBary[k] = halfedgeBary[firstEdge + index]; - } - } else if (numEdge == 4) { // Pair of triangles - int mapping[4] = {halfedge_[firstEdge].startVert, - halfedge_[firstEdge + 1].startVert, - halfedge_[firstEdge + 2].startVert, - halfedge_[firstEdge + 3].startVert}; - const glm::mat3x2 projection = GetAxisAlignedProjection(normal); - auto triCCW = [&projection, this](const glm::ivec3 tri) { - return CCW(projection * this->vertPos_[tri[0]], - projection * this->vertPos_[tri[1]], - projection * this->vertPos_[tri[2]], precision_) >= 0; - }; - - glm::ivec3 tri0(halfedge_[firstEdge].startVert, - halfedge_[firstEdge].endVert, -1); - glm::ivec3 tri1(-1, -1, tri0[0]); - for (const int i : {1, 2, 3}) { - if (halfedge_[firstEdge + i].startVert == tri0[1]) { - tri0[2] = halfedge_[firstEdge + i].endVert; - tri1[0] = tri0[2]; - } - if (halfedge_[firstEdge + i].endVert == tri0[0]) { - tri1[1] = halfedge_[firstEdge + i].startVert; - } - } - ASSERT(glm::all(glm::greaterThanEqual(tri0, glm::ivec3(0))) && - glm::all(glm::greaterThanEqual(tri1, glm::ivec3(0))), - topologyErr, "non-manifold quad!"); - bool firstValid = triCCW(tri0) && triCCW(tri1); - tri0[2] = tri1[1]; - tri1[2] = tri0[1]; - bool secondValid = triCCW(tri0) && triCCW(tri1); - - if (!secondValid) { - tri0[2] = tri1[0]; - tri1[2] = tri0[0]; - } else if (firstValid) { - glm::vec3 firstCross = vertPos_[tri0[0]] - vertPos_[tri1[0]]; - glm::vec3 secondCross = vertPos_[tri0[1]] - vertPos_[tri1[1]]; - if (glm::dot(firstCross, firstCross) < - glm::dot(secondCross, secondCross)) { - tri0[2] = tri1[0]; - tri1[2] = tri0[0]; - } - } - - for (auto tri : {tri0, tri1}) { - triVerts.push_back(tri); - triNormal.push_back(normal); - triBary.push_back(faceRef[face]); - for (int k : {0, 1, 2}) { - int index = linearSearch(mapping, tri[k]); - triBary.back().vertBary[k] = halfedgeBary[firstEdge + index]; - } - } - } else { // General triangulation - const glm::mat3x2 projection = GetAxisAlignedProjection(normal); - - std::map vertBary; - for (int j = firstEdge; j < lastEdge; ++j) - vertBary[halfedge_[j].startVert] = halfedgeBary[j]; - - const Polygons polys = Face2Polygons(face, projection, faceEdge); - - std::vector newTris = Triangulate(polys, precision_); - - for (auto tri : newTris) { - triVerts.push_back(tri); - triNormal.push_back(normal); - triBary.push_back(faceRef[face]); - for (int k : {0, 1, 2}) { - triBary.back().vertBary[k] = vertBary[tri[k]]; - } - } - } - } - faceNormal_ = std::move(triNormal); - CreateHalfedges(triVerts); -} - -/** - * For the input face index, return a set of 2D polygons formed by the input - * projection of the vertices. - */ -Polygons Manifold::Impl::Face2Polygons(int face, glm::mat3x2 projection, - const VecDH& faceEdge) const { - const int firstEdge = faceEdge[face]; - const int lastEdge = faceEdge[face + 1]; - - std::map vert_edge; - for (int edge = firstEdge; edge < lastEdge; ++edge) { - const bool inserted = - vert_edge.emplace(std::make_pair(halfedge_[edge].startVert, edge)) - .second; - ASSERT(inserted, topologyErr, "face has duplicate vertices."); - } - - Polygons polys; - int startEdge = 0; - int thisEdge = startEdge; - while (1) { - if (thisEdge == startEdge) { - if (vert_edge.empty()) break; - startEdge = vert_edge.begin()->second; - thisEdge = startEdge; - polys.push_back({}); - } - int vert = halfedge_[thisEdge].startVert; - polys.back().push_back({projection * vertPos_[vert], vert}); - const auto result = vert_edge.find(halfedge_[thisEdge].endVert); - ASSERT(result != vert_edge.end(), topologyErr, "non-manifold edge"); - thisEdge = result->second; - vert_edge.erase(result); - } - return polys; -} -} // namespace manifold diff --git a/IfcPlusPlus/src/external/manifold/src/manifold/src/impl.cpp b/IfcPlusPlus/src/external/manifold/src/manifold/src/impl.cpp deleted file mode 100644 index bc6e3253e..000000000 --- a/IfcPlusPlus/src/external/manifold/src/manifold/src/impl.cpp +++ /dev/null @@ -1,711 +0,0 @@ -// Copyright 2021 The Manifold Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "impl.h" - -#include - -#include -#include -#include - -#include "graph.h" -#include "hashtable.h" -#include "par.h" - -namespace { -using namespace manifold; - -__host__ __device__ void AtomicAddVec3(glm::vec3& target, - const glm::vec3& add) { - for (int i : {0, 1, 2}) { -#ifdef __CUDA_ARCH__ - atomicAdd(&target[i], add[i]); -#else - std::atomic& tar = reinterpret_cast&>(target[i]); - float old_val = tar.load(std::memory_order_relaxed); - while (!tar.compare_exchange_weak(old_val, old_val + add[i], - std::memory_order_relaxed)) - ; -#endif - } -} - -struct Normalize { - __host__ __device__ void operator()(glm::vec3& v) { v = SafeNormalize(v); } -}; - -struct Transform4x3 { - const glm::mat4x3 transform; - - __host__ __device__ glm::vec3 operator()(glm::vec3 position) { - return transform * glm::vec4(position, 1.0f); - } -}; - -struct TransformNormals { - const glm::mat3 transform; - - __host__ __device__ glm::vec3 operator()(glm::vec3 normal) { - normal = glm::normalize(transform * normal); - if (isnan(normal.x)) normal = glm::vec3(0.0f); - return normal; - } -}; - -struct AssignNormals { - glm::vec3* vertNormal; - const glm::vec3* vertPos; - const Halfedge* halfedges; - const float precision; - const bool calculateTriNormal; - - __host__ __device__ void operator()(thrust::tuple in) { - glm::vec3& triNormal = thrust::get<0>(in); - const int face = thrust::get<1>(in); - - glm::ivec3 triVerts; - for (int i : {0, 1, 2}) triVerts[i] = halfedges[3 * face + i].startVert; - - glm::vec3 edge[3]; - for (int i : {0, 1, 2}) { - const int j = (i + 1) % 3; - edge[i] = glm::normalize(vertPos[triVerts[j]] - vertPos[triVerts[i]]); - } - - if (calculateTriNormal) { - triNormal = glm::normalize(glm::cross(edge[0], edge[1])); - if (isnan(triNormal.x)) triNormal = glm::vec3(0, 0, 1); - } - - // corner angles - glm::vec3 phi; - float dot = -glm::dot(edge[2], edge[0]); - phi[0] = dot >= 1 ? 0 : (dot <= -1 ? glm::pi() : glm::acos(dot)); - dot = -glm::dot(edge[0], edge[1]); - phi[1] = dot >= 1 ? 0 : (dot <= -1 ? glm::pi() : glm::acos(dot)); - phi[2] = glm::pi() - phi[0] - phi[1]; - - // assign weighted sum - for (int i : {0, 1, 2}) { - AtomicAddVec3(vertNormal[triVerts[i]], phi[i] * triNormal); - } - } -}; - -struct Tri2Halfedges { - Halfedge* halfedges; - glm::uint64_t* edges; - - __host__ __device__ void operator()( - thrust::tuple in) { - const int tri = thrust::get<0>(in); - const glm::ivec3& triVerts = thrust::get<1>(in); - for (const int i : {0, 1, 2}) { - const int j = (i + 1) % 3; - const int edge = 3 * tri + i; - halfedges[edge] = {triVerts[i], triVerts[j], -1, tri}; - // Sort the forward halfedges in front of the backward ones by setting the - // highest-order bit. - edges[edge] = glm::uint64_t(triVerts[i] < triVerts[j] ? 1 : 0) << 63 | - ((glm::uint64_t)glm::min(triVerts[i], triVerts[j])) << 32 | - glm::max(triVerts[i], triVerts[j]); - } - } -}; - -struct LinkHalfedges { - Halfedge* halfedges; - const int* ids; - const int numEdge; - - __host__ __device__ void operator()(int i) { - const int pair0 = ids[i]; - const int pair1 = ids[i + numEdge]; - halfedges[pair0].pairedHalfedge = pair1; - halfedges[pair1].pairedHalfedge = pair0; - } -}; - -struct MarkVerts { - int* vert; - - __host__ __device__ void operator()(glm::ivec3 triVerts) { - for (int i : {0, 1, 2}) { - vert[triVerts[i]] = 1; - } - } -}; - -struct ReindexTriVerts { - const int* old2new; - - __host__ __device__ void operator()(glm::ivec3& triVerts) { - for (int i : {0, 1, 2}) { - triVerts[i] = old2new[triVerts[i]]; - } - } -}; - -struct InitializeBaryRef { - const int meshID; - const Halfedge* halfedge; - - __host__ __device__ void operator()(thrust::tuple inOut) { - BaryRef& baryRef = thrust::get<0>(inOut); - int tri = thrust::get<1>(inOut); - - baryRef.meshID = meshID; - baryRef.originalID = meshID; - baryRef.tri = tri; - baryRef.vertBary = {-3, -2, -1}; - } -}; - -struct MarkMeshID { - HashTableD table; - - __host__ __device__ void operator()(BaryRef& ref) { - if (table.Full()) return; - table.Insert(ref.meshID, 1); - } -}; - -struct UpdateMeshID { - const HashTableD meshIDold2new; - const int meshIDoffset; - - __host__ __device__ void operator()(BaryRef& ref) { - ref.meshID = meshIDold2new[ref.meshID] + meshIDoffset; - } -}; - -struct CheckProperties { - const int numSets; - - __host__ __device__ bool operator()(glm::ivec3 triProp) { - bool good = true; - for (int i : {0, 1, 2}) good &= (triProp[i] >= 0 && triProp[i] < numSets); - return good; - } -}; - -struct CoplanarEdge { - float* triArea; - const Halfedge* halfedge; - const glm::vec3* vertPos; - const glm::ivec3* triProp; - const float* prop; - const float* propTol; - const int numProp; - const float precision; - - __host__ __device__ void operator()( - thrust::tuple&, int> inOut) { - thrust::pair& face2face = thrust::get<0>(inOut); - const int edgeIdx = thrust::get<1>(inOut); - - const Halfedge edge = halfedge[edgeIdx]; - if (!edge.IsForward()) return; - const Halfedge pair = halfedge[edge.pairedHalfedge]; - const glm::vec3 base = vertPos[edge.startVert]; - - const int baseNum = edgeIdx - 3 * edge.face; - const int jointNum = edge.pairedHalfedge - 3 * pair.face; - const int edgeNum = baseNum == 0 ? 2 : baseNum - 1; - const int pairNum = jointNum == 0 ? 2 : jointNum - 1; - - const glm::vec3 jointVec = vertPos[pair.startVert] - base; - const glm::vec3 edgeVec = - vertPos[halfedge[3 * edge.face + edgeNum].startVert] - base; - const glm::vec3 pairVec = - vertPos[halfedge[3 * pair.face + pairNum].startVert] - base; - - const float length = glm::max(glm::length(jointVec), glm::length(edgeVec)); - const float lengthPair = - glm::max(glm::length(jointVec), glm::length(pairVec)); - glm::vec3 normal = glm::cross(jointVec, edgeVec); - const float area = glm::length(normal); - const float areaPair = glm::length(glm::cross(pairVec, jointVec)); - // Don't link degenerate triangles - if (area < length * precision || areaPair < lengthPair * precision) return; - - const float volume = glm::abs(glm::dot(normal, pairVec)); - // Only operate on coplanar triangles - if (volume > glm::max(area, areaPair) * precision) return; - - // Check property linearity - if (area > 0) { - normal /= area; - for (int i = 0; i < numProp; ++i) { - const float scale = precision / propTol[i]; - - const float baseProp = prop[numProp * triProp[edge.face][baseNum] + i]; - const float jointProp = - prop[numProp * triProp[pair.face][jointNum] + i]; - const float edgeProp = prop[numProp * triProp[edge.face][edgeNum] + i]; - const float pairProp = prop[numProp * triProp[pair.face][pairNum] + i]; - - const glm::vec3 iJointVec = - jointVec + normal * scale * (jointProp - baseProp); - const glm::vec3 iEdgeVec = - edgeVec + normal * scale * (edgeProp - baseProp); - const glm::vec3 iPairVec = - pairVec + normal * scale * (pairProp - baseProp); - - glm::vec3 cross = glm::cross(iJointVec, iEdgeVec); - const float area = glm::max( - glm::length(cross), glm::length(glm::cross(iPairVec, iJointVec))); - const float volume = glm::abs(glm::dot(cross, iPairVec)); - // Only operate on consistent triangles - if (volume > area * precision) return; - } - } - - triArea[edge.face] = area; - triArea[pair.face] = areaPair; - face2face.first = edge.face; - face2face.second = pair.face; - } -}; - -struct EdgeBox { - const glm::vec3* vertPos; - - __host__ __device__ void operator()( - thrust::tuple inout) { - const TmpEdge& edge = thrust::get<1>(inout); - thrust::get<0>(inout) = Box(vertPos[edge.first], vertPos[edge.second]); - } -}; - -} // namespace - -namespace manifold { - -std::atomic Manifold::Impl::meshIDCounter_(1); - -/** - * Create a manifold from an input triangle Mesh. Will return an empty Manifold - * and set an Error Status if the Mesh is not manifold or otherwise invalid. - * TODO: update halfedgeTangent during SimplifyTopology. - */ -Manifold::Impl::Impl(const Mesh& mesh, - const std::vector& triProperties, - const std::vector& properties, - const std::vector& propertyTolerance) - : vertPos_(mesh.vertPos), - halfedgeTangent_(mesh.halfedgeTangent), - meshids(1) { - VecDH triVerts = mesh.triVerts; - if (!IsIndexInBounds(triVerts)) { - MarkFailure(Error::VERTEX_INDEX_OUT_OF_BOUNDS); - return; - } - RemoveUnreferencedVerts(triVerts); - - CalculateBBox(); - if (!IsFinite()) { - MarkFailure(Error::NON_FINITE_VERTEX); - return; - } - SetPrecision(); - - CreateHalfedges(triVerts); - if (!IsManifold()) { - MarkFailure(Error::NOT_MANIFOLD); - return; - } - CalculateNormals(); - InitializeNewReference(triProperties, properties, propertyTolerance); - if (status_ != Error::NO_ERROR) return; - - SimplifyTopology(); - Finish(); -} - -/** - * Create either a unit tetrahedron, cube or octahedron. The cube is in the - * first octant, while the others are symmetric about the origin. - */ -Manifold::Impl::Impl(Shape shape) : meshids(1) { - std::vector vertPos; - std::vector triVerts; - switch (shape) { - case Shape::TETRAHEDRON: - vertPos = {{-1.0f, -1.0f, 1.0f}, - {-1.0f, 1.0f, -1.0f}, - {1.0f, -1.0f, -1.0f}, - {1.0f, 1.0f, 1.0f}}; - triVerts = {{2, 0, 1}, {0, 3, 1}, {2, 3, 0}, {3, 2, 1}}; - break; - case Shape::CUBE: - vertPos = {{0.0f, 0.0f, 0.0f}, // - {1.0f, 0.0f, 0.0f}, // - {1.0f, 1.0f, 0.0f}, // - {0.0f, 1.0f, 0.0f}, // - {0.0f, 0.0f, 1.0f}, // - {1.0f, 0.0f, 1.0f}, // - {1.0f, 1.0f, 1.0f}, // - {0.0f, 1.0f, 1.0f}}; - triVerts = {{0, 2, 1}, {0, 3, 2}, // - {4, 5, 6}, {4, 6, 7}, // - {0, 1, 5}, {0, 5, 4}, // - {1, 2, 6}, {1, 6, 5}, // - {2, 3, 7}, {2, 7, 6}, // - {3, 0, 4}, {3, 4, 7}}; - break; - case Shape::OCTAHEDRON: - vertPos = {{1.0f, 0.0f, 0.0f}, // - {-1.0f, 0.0f, 0.0f}, // - {0.0f, 1.0f, 0.0f}, // - {0.0f, -1.0f, 0.0f}, // - {0.0f, 0.0f, 1.0f}, // - {0.0f, 0.0f, -1.0f}}; - triVerts = {{0, 2, 4}, {1, 5, 3}, // - {2, 1, 4}, {3, 5, 0}, // - {1, 3, 4}, {0, 5, 2}, // - {3, 0, 4}, {2, 5, 1}}; - break; - } - vertPos_ = vertPos; - CreateHalfedges(triVerts); - Finish(); - InitializeNewReference(); -} - -void Manifold::Impl::RemoveUnreferencedVerts(VecDH& triVerts) { - VecDH vertOld2New(NumVert() + 1, 0); - auto policy = autoPolicy(NumVert()); - for_each(policy, triVerts.cbegin(), triVerts.cend(), - MarkVerts({vertOld2New.ptrD() + 1})); - - const VecDH oldVertPos = vertPos_; - vertPos_.resize(copy_if( - policy, oldVertPos.cbegin(), oldVertPos.cend(), - vertOld2New.cbegin() + 1, vertPos_.begin(), - thrust::identity()) - - vertPos_.begin()); - - inclusive_scan(policy, vertOld2New.begin() + 1, vertOld2New.end(), - vertOld2New.begin() + 1); - - for_each(policy, triVerts.begin(), triVerts.end(), - ReindexTriVerts({vertOld2New.cptrD()})); -} - -void Manifold::Impl::ReinitializeReference(int meshID) { - // instead of storing the meshID, we store 0 and set the mapping to - // 0 -> meshID, because the meshID after boolean operation also starts from 0. - for_each_n(autoPolicy(NumTri()), - zip(meshRelation_.triBary.begin(), countAt(0)), NumTri(), - InitializeBaryRef({meshID, halfedge_.cptrD()})); - meshRelation_.originalID = meshID; - meshids = 1; -} - -int Manifold::Impl::InitializeNewReference( - const std::vector& triProperties, - const std::vector& properties, - const std::vector& propertyTolerance) { - meshRelation_.triBary.resize(NumTri()); - const int nextMeshID = meshIDCounter_.fetch_add(1, std::memory_order_relaxed); - ReinitializeReference(nextMeshID); - - const int numProps = propertyTolerance.size(); - - VecDH triPropertiesD(triProperties); - VecDH propertiesD(properties); - VecDH propertyToleranceD(propertyTolerance); - - if (numProps > 0) { - if (triProperties.size() != NumTri() && triProperties.size() != 0) { - MarkFailure(Error::TRI_PROPERTIES_WRONG_LENGTH); - return nextMeshID; - }; - if (properties.size() % numProps != 0) { - MarkFailure(Error::PROPERTIES_WRONG_LENGTH); - return nextMeshID; - }; - - const int numSets = properties.size() / numProps; - if (!all_of(autoPolicy(triProperties.size()), triPropertiesD.begin(), - triPropertiesD.end(), CheckProperties({numSets}))) { - MarkFailure(Error::TRI_PROPERTIES_OUT_OF_BOUNDS); - return nextMeshID; - }; - } - - VecDH> face2face(halfedge_.size(), {-1, -1}); - VecDH triArea(NumTri()); - for_each_n(autoPolicy(halfedge_.size()), zip(face2face.begin(), countAt(0)), - halfedge_.size(), - CoplanarEdge({triArea.ptrD(), halfedge_.cptrD(), vertPos_.cptrD(), - triPropertiesD.cptrD(), propertiesD.cptrD(), - propertyToleranceD.cptrD(), numProps, precision_})); - - Graph graph; - for (int i = 0; i < NumTri(); ++i) { - graph.add_nodes(i); - } - for (int i = 0; i < face2face.size(); ++i) { - const thrust::pair edge = face2face[i]; - if (edge.first < 0) continue; - graph.add_edge(edge.first, edge.second); - } - - std::vector components; - const int numComponent = ConnectedComponents(components, graph); - - std::vector comp2tri(numComponent, -1); - for (int tri = 0; tri < NumTri(); ++tri) { - const int comp = components[tri]; - const int current = comp2tri[comp]; - if (current < 0 || triArea[tri] > triArea[current]) { - comp2tri[comp] = tri; - triArea[comp] = triArea[tri]; - } - } - - VecDH& triBary = meshRelation_.triBary; - std::map, int> triVert2bary; - - for (int tri = 0; tri < NumTri(); ++tri) { - const int refTri = comp2tri[components[tri]]; - if (refTri == tri) continue; - - glm::mat3 triPos; - for (int i : {0, 1, 2}) { - const int vert = halfedge_[3 * refTri + i].startVert; - triPos[i] = vertPos_[vert]; - triVert2bary[{refTri, vert}] = i - 3; - } - - glm::ivec3 vertBary; - bool coplanar = true; - for (int i : {0, 1, 2}) { - const int vert = halfedge_[3 * tri + i].startVert; - if (triVert2bary.find({refTri, vert}) == triVert2bary.end()) { - const glm::vec3 uvw = - GetBarycentric(vertPos_[vert], triPos, precision_); - if (isnan(uvw[0])) { - coplanar = false; - triVert2bary[{refTri, vert}] = -4; - break; - } - triVert2bary[{refTri, vert}] = meshRelation_.barycentric.size(); - meshRelation_.barycentric.push_back(uvw); - } - const int bary = triVert2bary[{refTri, vert}]; - if (bary < -3) { - coplanar = false; - break; - } - vertBary[i] = bary; - } - - if (coplanar) { - BaryRef& ref = triBary[tri]; - ref.tri = refTri; - ref.vertBary = vertBary; - } - } - - return nextMeshID; -} - -/** - * Create the halfedge_ data structure from an input triVerts array like Mesh. - */ -void Manifold::Impl::CreateHalfedges(const VecDH& triVerts) { - const int numTri = triVerts.size(); - const int numEdge = 3 * numTri / 2; - // drop the old value first to avoid copy - halfedge_.resize(0); - halfedge_.resize(2 * numEdge); - VecDH edge(2 * numEdge); - VecDH ids(2 * numEdge); - auto policy = autoPolicy(numTri); - sequence(policy, ids.begin(), ids.end()); - for_each_n(policy, zip(countAt(0), triVerts.begin()), numTri, - Tri2Halfedges({halfedge_.ptrD(), edge.ptrD()})); - // Stable sort is required here so that halfedges from the same face are - // paired together (the triangles were created in face order). In some - // degenerate situations the triangulator can add the same internal edge in - // two different faces, causing this edge to not be 2-manifold. These are - // fixed by duplicating verts in SimplifyTopology. - stable_sort_by_key(policy, edge.begin(), edge.end(), ids.begin()); - // Once sorted, the first half of the range is the forward halfedges, which - // correspond to their backward pair at the same offset in the second half - // of the range. - for_each_n(policy, countAt(0), numEdge, - LinkHalfedges({halfedge_.ptrD(), ids.ptrD(), numEdge})); -} - -/** - * Does a full recalculation of the face bounding boxes, including updating the - * collider, but does not resort the faces. - */ -void Manifold::Impl::Update() { - CalculateBBox(); - VecDH faceBox; - VecDH faceMorton; - GetFaceBoxMorton(faceBox, faceMorton); - collider_.UpdateBoxes(faceBox); -} - -void Manifold::Impl::MarkFailure(Error status) { - bBox_ = Box(); - vertPos_.resize(0); - halfedge_.resize(0); - vertNormal_.resize(0); - faceNormal_.resize(0); - halfedgeTangent_.resize(0); - meshRelation_ = MeshRelationD(); - status_ = status; -} - -Manifold::Impl Manifold::Impl::Transform(const glm::mat4x3& transform_) const { - if (transform_ == glm::mat4x3(1.0f)) return *this; - auto policy = autoPolicy(NumVert()); - Impl result; - result.meshids = meshids; - result.collider_ = collider_; - result.meshRelation_ = meshRelation_; - result.precision_ = precision_; - result.bBox_ = bBox_; - result.halfedge_ = halfedge_; - result.halfedgeTangent_ = halfedgeTangent_; - - result.vertPos_.resize(NumVert()); - result.faceNormal_.resize(faceNormal_.size()); - result.vertNormal_.resize(vertNormal_.size()); - transform(policy, vertPos_.begin(), vertPos_.end(), result.vertPos_.begin(), - Transform4x3({transform_})); - - glm::mat3 normalTransform = - glm::inverse(glm::transpose(glm::mat3(transform_))); - transform(policy, faceNormal_.begin(), faceNormal_.end(), - result.faceNormal_.begin(), TransformNormals({normalTransform})); - transform(policy, vertNormal_.begin(), vertNormal_.end(), - result.vertNormal_.begin(), TransformNormals({normalTransform})); - // This optimization does a cheap collider update if the transform is - // axis-aligned. - if (!result.collider_.Transform(transform_)) result.Update(); - - result.CalculateBBox(); - float scale = 0; - for (int i : {0, 1, 2}) - scale = - glm::max(scale, transform_[0][i] + transform_[1][i] + transform_[2][i]); - result.precision_ *= scale; - // Maximum of inherited precision loss and translational precision loss. - result.SetPrecision(result.precision_); - return result; -} - -/** - * Sets the precision based on the bounding box, and limits its minimum value by - * the optional input. - */ -void Manifold::Impl::SetPrecision(float minPrecision) { - precision_ = glm::max(minPrecision, kTolerance * bBox_.Scale()); - if (!glm::isfinite(precision_)) precision_ = -1; -} - -/** - * If face normals are already present, this function uses them to compute - * vertex normals (angle-weighted pseudo-normals); otherwise it also computes - * the face normals. Face normals are only calculated when needed because nearly - * degenerate faces will accrue rounding error, while the Boolean can retain - * their original normal, which is more accurate and can help with merging - * coplanar faces. - * - * If the face normals have been invalidated by an operation like Warp(), ensure - * you do faceNormal_.resize(0) before calling this function to force - * recalculation. - */ -void Manifold::Impl::CalculateNormals() { - vertNormal_.resize(NumVert()); - auto policy = autoPolicy(NumTri()); - fill(policy, vertNormal_.begin(), vertNormal_.end(), glm::vec3(0)); - bool calculateTriNormal = false; - if (faceNormal_.size() != NumTri()) { - faceNormal_.resize(NumTri()); - calculateTriNormal = true; - } - for_each_n( - policy, zip(faceNormal_.begin(), countAt(0)), NumTri(), - AssignNormals({vertNormal_.ptrD(), vertPos_.cptrD(), halfedge_.cptrD(), - precision_, calculateTriNormal})); - for_each(policy, vertNormal_.begin(), vertNormal_.end(), Normalize()); -} - -/** - * Remaps all the contained meshIDs to new unique values to represent new - * instances of these meshes. - */ -void Manifold::Impl::IncrementMeshIDs(int start, int length) { - VecDH& triBary = meshRelation_.triBary; - ASSERT(start >= 0 && length >= 0 && start + length <= triBary.size(), - logicErr, "out of bounds"); - const auto policy = autoPolicy(length); - HashTable meshidTable(std::max(16u, meshids * 2)); - - auto begin = triBary.begin() + start; - auto end = begin + length; - while (1) { - for_each(policy, begin, end, MarkMeshID({meshidTable.D()})); - if (!meshidTable.Full()) break; - meshidTable = HashTable(meshidTable.Size() * 2); - } - inclusive_scan( - autoPolicy(meshidTable.Size()), meshidTable.GetValueStore().begin(), - meshidTable.GetValueStore().end(), meshidTable.GetValueStore().begin()); - const int numMeshIDs = meshidTable.GetValueStore().back(); - const int meshIDstart = Manifold::Impl::meshIDCounter_.fetch_add( - numMeshIDs, std::memory_order_relaxed); - // We do start - 1 because the inclusive scan makes our first index 1 instead - // of 0. - for_each(policy, begin, end, UpdateMeshID({meshidTable.D(), meshIDstart})); -} - -/** - * Returns a sparse array of the bounding box overlaps between the edges of the - * input manifold, Q and the faces of this manifold. Returned indices only - * point to forward halfedges. - */ -SparseIndices Manifold::Impl::EdgeCollisions(const Impl& Q) const { - VecDH edges = CreateTmpEdges(Q.halfedge_); - const int numEdge = edges.size(); - VecDH QedgeBB(numEdge); - auto policy = autoPolicy(numEdge); - for_each_n(policy, zip(QedgeBB.begin(), edges.cbegin()), numEdge, - EdgeBox({Q.vertPos_.cptrD()})); - - SparseIndices q1p2 = collider_.Collisions(QedgeBB); - - for_each(policy, q1p2.begin(0), q1p2.end(0), ReindexEdge({edges.cptrD()})); - return q1p2; -} - -/** - * Returns a sparse array of the input vertices that project inside the XY - * bounding boxes of the faces of this manifold. - */ -SparseIndices Manifold::Impl::VertexCollisionsZ( - const VecDH& vertsIn) const { - return collider_.Collisions(vertsIn); -} -} // namespace manifold diff --git a/IfcPlusPlus/src/external/manifold/src/manifold/src/impl.h b/IfcPlusPlus/src/external/manifold/src/manifold/src/impl.h deleted file mode 100644 index ab69c9335..000000000 --- a/IfcPlusPlus/src/external/manifold/src/manifold/src/impl.h +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright 2021 The Manifold Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once -#include "collider.h" -#include "manifold.h" -#include "optional_assert.h" -#include "shared.h" -#include "sparse.h" -#include "utils.h" -#include "vec_dh.h" - -namespace manifold { - -/** @ingroup Private */ -struct Manifold::Impl { - struct MeshRelationD { - VecDH barycentric; - VecDH triBary; - /// The meshID of this Manifold if it is an original; -1 otherwise. - int originalID = -1; - }; - - Box bBox_; - float precision_ = -1; - Error status_ = Error::NO_ERROR; - VecDH vertPos_; - VecDH halfedge_; - VecDH vertNormal_; - VecDH faceNormal_; - VecDH halfedgeTangent_; - MeshRelationD meshRelation_; - Collider collider_; - unsigned int meshids = 1; - - static std::atomic meshIDCounter_; - - Impl() {} - enum class Shape { TETRAHEDRON, CUBE, OCTAHEDRON }; - Impl(Shape); - - Impl(const Mesh&, - const std::vector& triProperties = std::vector(), - const std::vector& properties = std::vector(), - const std::vector& propertyTolerance = std::vector()); - - int InitializeNewReference( - const std::vector& triProperties = std::vector(), - const std::vector& properties = std::vector(), - const std::vector& propertyTolerance = std::vector()); - - void RemoveUnreferencedVerts(VecDH& triVerts); - void ReinitializeReference(int meshID); - void CreateHalfedges(const VecDH& triVerts); - void CalculateNormals(); - void IncrementMeshIDs(int start, int length); - - void Update(); - void MarkFailure(Error status); - Impl Transform(const glm::mat4x3& transform) const; - SparseIndices EdgeCollisions(const Impl& B) const; - SparseIndices VertexCollisionsZ(const VecDH& vertsIn) const; - - bool IsEmpty() const { return NumVert() == 0; } - int NumVert() const { return vertPos_.size(); } - int NumEdge() const { return halfedge_.size() / 2; } - int NumTri() const { return halfedge_.size() / 3; } - - // properties.cu - Properties GetProperties() const; - Curvature GetCurvature() const; - void CalculateBBox(); - bool IsFinite() const; - bool IsIndexInBounds(const VecDH& triVerts) const; - void SetPrecision(float minPrecision = -1); - bool IsManifold() const; - bool Is2Manifold() const; - bool MatchesTriNormals() const; - int NumDegenerateTris() const; - - // sort.cu - void Finish(); - void SortVerts(); - void ReindexVerts(const VecDH& vertNew2Old, int numOldVert); - void GetFaceBoxMorton(VecDH& faceBox, VecDH& faceMorton) const; - void SortFaces(VecDH& faceBox, VecDH& faceMorton); - void GatherFaces(const VecDH& faceNew2Old); - void GatherFaces(const Impl& old, const VecDH& faceNew2Old); - - // face_op.cu - void Face2Tri(const VecDH& faceEdge, const VecDH& faceRef, - const VecDH& halfedgeBary); - Polygons Face2Polygons(int face, glm::mat3x2 projection, - const VecDH& faceEdge) const; - - // edge_op.cu - void SimplifyTopology(); - void DedupeEdge(int edge); - void CollapseEdge(int edge); - void RecursiveEdgeSwap(int edge); - void RemoveIfFolded(int edge); - void PairUp(int edge0, int edge1); - void UpdateVert(int vert, int startEdge, int endEdge); - void FormLoop(int current, int end); - void CollapseTri(const glm::ivec3& triEdge); - - // smoothing.cu - void CreateTangents(const std::vector&); - MeshRelationD Subdivide(int n); - void Refine(int n); -}; -} // namespace manifold diff --git a/IfcPlusPlus/src/external/manifold/src/manifold/src/manifold.cpp b/IfcPlusPlus/src/external/manifold/src/manifold/src/manifold.cpp deleted file mode 100644 index e3b8f6c3b..000000000 --- a/IfcPlusPlus/src/external/manifold/src/manifold/src/manifold.cpp +++ /dev/null @@ -1,615 +0,0 @@ -// Copyright 2021 The Manifold Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "boolean3.h" -#include "csg_tree.h" -#include "impl.h" -#include "par.h" - -namespace { -using namespace manifold; -using namespace thrust::placeholders; - -ExecutionParams params; - -struct MakeTri { - const Halfedge* halfedges; - - __host__ __device__ void operator()(thrust::tuple inOut) { - glm::ivec3& tri = thrust::get<0>(inOut); - const int face = 3 * thrust::get<1>(inOut); - - for (int i : {0, 1, 2}) { - tri[i] = halfedges[face + i].startVert; - } - } -}; - -Manifold Halfspace(Box bBox, glm::vec3 normal, float originOffset) { - normal = glm::normalize(normal); - Manifold cutter = - Manifold::Cube(glm::vec3(2.0f), true).Translate({1.0f, 0.0f, 0.0f}); - float size = glm::length(bBox.Center() - normal * originOffset) + - 0.5f * glm::length(bBox.Size()); - cutter = cutter.Scale(glm::vec3(size)).Translate({originOffset, 0.0f, 0.0f}); - float yDeg = glm::degrees(-glm::asin(normal.z)); - float zDeg = glm::degrees(glm::atan(normal.y, normal.x)); - return cutter.Rotate(0.0f, yDeg, zDeg); -} -} // namespace - -namespace manifold { - -/** - * Construct an empty Manifold. - * - */ -Manifold::Manifold() : pNode_{std::make_shared()} {} -Manifold::~Manifold() = default; -Manifold::Manifold(Manifold&&) noexcept = default; -Manifold& Manifold::operator=(Manifold&&) noexcept = default; - -Manifold::Manifold(const Manifold& other) : pNode_(other.pNode_) {} - -Manifold::Manifold(std::shared_ptr pNode) : pNode_(pNode) {} - -Manifold::Manifold(std::shared_ptr pImpl_) - : pNode_(std::make_shared(pImpl_)) {} - -Manifold& Manifold::operator=(const Manifold& other) { - if (this != &other) { - pNode_ = other.pNode_; - } - return *this; -} - -CsgLeafNode& Manifold::GetCsgLeafNode() const { - if (pNode_->GetNodeType() != CsgNodeType::LEAF) { - pNode_ = pNode_->ToLeafNode(); - } - return *std::static_pointer_cast(pNode_); -} - -/** - * Convert a Mesh into a Manifold. Will return an empty Manifold - * and set an Error Status if the Mesh is not an oriented 2-manifold. Will - * collapse degenerate triangles and unnecessary vertices. - * - * The three optional inputs should all be specified if any are. These define - * any properties you may have on this mesh. These properties are not saved in - * the Manifold, but rather used to determine which coplanar triangles can be - * safely merged due to all properties being colinear. Any edges that define - * property boundaries will be retained in the output of arbitrary Boolean - * operations so that these properties can be properly reapplied to the result - * using the MeshRelation. - * - * @param mesh The input Mesh. - * @param triProperties A vector of the same length as triVerts, filled with - * references to the properties index. Note the same vertex can have different - * properties in different triangles. - * @param properties A vector whose length is the largest index in - * triProperties times the length of propertyTolerance (the number of - * properties). Think of it as a property matrix indexed as [index * - * numProperties + propertyNum]. - * @param propertyTolerance A vector of precision values for each property. - * This is the amount of interpolation error allowed before two neighboring - * triangles are considered not coplanar. A good place to start is 1e-5 times - * the largest value you expect this property to take. - */ -Manifold::Manifold(const Mesh& mesh, - const std::vector& triProperties, - const std::vector& properties, - const std::vector& propertyTolerance) - : pNode_(std::make_shared(std::make_shared( - mesh, triProperties, properties, propertyTolerance))) {} - -/** - * This returns a Mesh of simple vectors of vertices and triangles suitable for - * saving or other operations outside of the context of this library. - */ -Mesh Manifold::GetMesh() const { - const Impl& impl = *GetCsgLeafNode().GetImpl(); - - Mesh result; - result.vertPos.insert(result.vertPos.end(), impl.vertPos_.begin(), - impl.vertPos_.end()); - result.vertNormal.insert(result.vertNormal.end(), impl.vertNormal_.begin(), - impl.vertNormal_.end()); - result.halfedgeTangent.insert(result.halfedgeTangent.end(), - impl.halfedgeTangent_.begin(), - impl.halfedgeTangent_.end()); - - result.triVerts.resize(NumTri()); - // note that `triVerts` is `std::vector`, so we cannot use thrust::device - thrust::for_each_n(thrust::host, zip(result.triVerts.begin(), countAt(0)), - NumTri(), MakeTri({impl.halfedge_.cptrH()})); - - return result; -} - -MeshGL Manifold::GetMeshGL() const { - const Impl& impl = *GetCsgLeafNode().GetImpl(); - - const int numVert = NumVert(); - const int numTri = NumTri(); - - MeshGL out; - out.vertPos.resize(3 * numVert); - out.vertNormal.resize(3 * numVert); - out.triVerts.resize(3 * numTri); - for (int i = 0; i < numVert; ++i) { - const glm::vec3 v = impl.vertPos_[i]; - out.vertPos[3 * i] = v.x; - out.vertPos[3 * i + 1] = v.y; - out.vertPos[3 * i + 2] = v.z; - const glm::vec3 n = impl.vertNormal_[i]; - out.vertNormal[3 * i] = n.x; - out.vertNormal[3 * i + 1] = n.y; - out.vertNormal[3 * i + 2] = n.z; - } - for (int i = 0; i < numTri * 3; ++i) { - out.triVerts[i] = impl.halfedge_[i].startVert; - } - const int numHalfedge = impl.halfedgeTangent_.size(); - out.halfedgeTangent.resize(4 * numHalfedge); - for (int i = 0; i < numHalfedge; ++i) { - const glm::vec4 t = impl.halfedgeTangent_[i]; - out.halfedgeTangent[4 * i] = t.x; - out.halfedgeTangent[4 * i + 1] = t.y; - out.halfedgeTangent[4 * i + 2] = t.z; - out.halfedgeTangent[4 * i + 3] = t.w; - } - - return out; -} - -int Manifold::circularSegments_ = 0; -float Manifold::circularAngle_ = 10.0f; -float Manifold::circularEdgeLength_ = 1.0f; - -/** - * Sets an angle constraint the default number of circular segments for the - * Cylinder(), Sphere(), and Revolve() constructors. The number of segments will - * be rounded up to the nearest factor of four. - * - * @param angle The minimum angle in degrees between consecutive segments. The - * angle will increase if the the segments hit the minimum edge length. Default - * is 10 degrees. - */ -void Manifold::SetMinCircularAngle(float angle) { - if (angle <= 0) return; - Manifold::circularAngle_ = angle; -} - -/** - * Sets a length constraint the default number of circular segments for the - * Cylinder(), Sphere(), and Revolve() constructors. The number of segments will - * be rounded up to the nearest factor of four. - * - * @param length The minimum length of segments. The length will - * increase if the the segments hit the minimum angle. Default is 1.0. - */ -void Manifold::SetMinCircularEdgeLength(float length) { - if (length <= 0) return; - Manifold::circularEdgeLength_ = length; -} - -/** - * Sets the default number of circular segments for the - * Cylinder(), Sphere(), and Revolve() constructors. Overrides the edge length - * and angle constraints and sets the number of segments to exactly this value. - * - * @param number Number of circular segments. Default is 0, meaning no - * constraint is applied. - */ -void Manifold::SetCircularSegments(int number) { - if (number < 3 && number != 0) return; - Manifold::circularSegments_ = number; -} - -/** - * Determine the result of the SetMinCircularAngle(), - * SetMinCircularEdgeLength(), and SetCircularSegments() defaults. - * - * @param radius For a given radius of circle, determine how many default - * segments there will be. - */ -int Manifold::GetCircularSegments(float radius) { - if (Manifold::circularSegments_ > 0) return Manifold::circularSegments_; - int nSegA = 360.0f / Manifold::circularAngle_; - int nSegL = 2.0f * radius * glm::pi() / Manifold::circularEdgeLength_; - int nSeg = fmin(nSegA, nSegL) + 3; - nSeg -= nSeg % 4; - return nSeg; -} - -/** - * Does the Manifold have any triangles? - */ -bool Manifold::IsEmpty() const { return GetCsgLeafNode().GetImpl()->IsEmpty(); } -/** - * Returns the reason for an input Mesh producing an empty Manifold. This Status - * only applies to Manifolds newly-created from an input Mesh - once they are - * combined into a new Manifold via operations, the status reverts to NO_ERROR, - * simply processing the problem mesh as empty. Likewise, empty meshes may still - * show NO_ERROR, for instance if they are small enough relative to their - * precision to be collapsed to nothing. - */ -Manifold::Error Manifold::Status() const { - return GetCsgLeafNode().GetImpl()->status_; -} -/** - * The number of vertices in the Manifold. - */ -int Manifold::NumVert() const { return GetCsgLeafNode().GetImpl()->NumVert(); } -/** - * The number of edges in the Manifold. - */ -int Manifold::NumEdge() const { return GetCsgLeafNode().GetImpl()->NumEdge(); } -/** - * The number of triangles in the Manifold. - */ -int Manifold::NumTri() const { return GetCsgLeafNode().GetImpl()->NumTri(); } - -/** - * Returns the axis-aligned bounding box of all the Manifold's vertices. - */ -Box Manifold::BoundingBox() const { return GetCsgLeafNode().GetImpl()->bBox_; } - -/** - * Returns the precision of this Manifold's vertices, which tracks the - * approximate rounding error over all the transforms and operations that have - * led to this state. Any triangles that are colinear within this precision are - * considered degenerate and removed. This is the value of ε defining - * [ε-valid](https://github.com/elalish/manifold/wiki/Manifold-Library#definition-of-%CE%B5-valid). - */ -float Manifold::Precision() const { - return GetCsgLeafNode().GetImpl()->precision_; -} - -/** - * The genus is a topological property of the manifold, representing the number - * of "handles". A sphere is 0, torus 1, etc. It is only meaningful for a single - * mesh, so it is best to call Decompose() first. - */ -int Manifold::Genus() const { - int chi = NumVert() - NumEdge() + NumTri(); - return 1 - chi / 2; -} - -/** - * Returns the surface area and volume of the manifold. These properties are - * clamped to zero for a given face if they are within the Precision(). This - * means degenerate manifolds can by identified by testing these properties as - * == 0. - */ -Properties Manifold::GetProperties() const { - return GetCsgLeafNode().GetImpl()->GetProperties(); -} - -/** - * Curvature is the inverse of the radius of curvature, and signed such that - * positive is convex and negative is concave. There are two orthogonal - * principal curvatures at any point on a manifold, with one maximum and the - * other minimum. Gaussian curvature is their product, while mean - * curvature is their sum. This approximates them for every vertex (returned as - * vectors in the structure) and also returns their minimum and maximum values. - */ -Curvature Manifold::GetCurvature() const { - return GetCsgLeafNode().GetImpl()->GetCurvature(); -} - -/** - * Gets the relationship to the previous meshes, for the purpose of assigning - * properties like texture coordinates. The triBary vector is the same length as - * Mesh.triVerts: BaryRef.originalID indicates the source mesh and BaryRef.tri - * is that mesh's triangle index to which these barycentric coordinates refer. - * BaryRef.vertBary gives an index for each vertex into the barycentric vector - * if that index is >= 0, indicating it is a new vertex. If the index is < 0, - * this indicates it is an original vertex, the index + 3 vert of the referenced - * triangle. - * - * BaryRef.meshID is a unique ID to the particular instance of a given mesh. For - * instance, if you want to convert the triangle mesh to a polygon mesh, all the - * triangles from a given face will have the same .meshID and .tri values. - */ -MeshRelation Manifold::GetMeshRelation() const { - MeshRelation out; - const auto& relation = GetCsgLeafNode().GetImpl()->meshRelation_; - out.triBary.insert(out.triBary.end(), relation.triBary.begin(), - relation.triBary.end()); - out.barycentric.insert(out.barycentric.end(), relation.barycentric.begin(), - relation.barycentric.end()); - return out; -} - -/** - * If this mesh is an original, this returns its meshID that can be referenced - * by product manifolds' MeshRelation. If this manifold is a product, this - * returns -1. - */ -int Manifold::OriginalID() const { - return GetCsgLeafNode().GetImpl()->meshRelation_.originalID; -} - -/** - * If you copy a manifold, but you want this new copy to have new properties - * (e.g. a different UV mapping), you can reset its meshIDs to a new original, - * meaning it will now be referenced by its descendents instead of the meshes it - * was built from, allowing you to differentiate the copies when applying your - * properties to the final result. - * - * This function also condenses all coplanar faces in the relation, and - * collapses those edges. If you want to have inconsistent properties across - * these faces, meaning you want to preserve some of these edges, you should - * instead call GetMesh(), calculate your properties and use these to construct - * a new manifold. - */ -Manifold Manifold::AsOriginal() const { - auto newImpl = std::make_shared(*GetCsgLeafNode().GetImpl()); - newImpl->InitializeNewReference(); - newImpl->SimplifyTopology(); - newImpl->Finish(); - return Manifold(std::make_shared(newImpl)); -} - -/** - * Should always be true. Also checks saneness of the internal data structures. - */ -bool Manifold::IsManifold() const { - return GetCsgLeafNode().GetImpl()->Is2Manifold(); -} - -/** - * The triangle normal vectors are saved over the course of operations rather - * than recalculated to avoid rounding error. This checks that triangles still - * match their normal vectors within Precision(). - */ -bool Manifold::MatchesTriNormals() const { - return GetCsgLeafNode().GetImpl()->MatchesTriNormals(); -} - -/** - * The number of triangles that are colinear within Precision(). This library - * attempts to remove all of these, but it cannot always remove all of them - * without changing the mesh by too much. - */ -int Manifold::NumDegenerateTris() const { - return GetCsgLeafNode().GetImpl()->NumDegenerateTris(); -} - -/** - * This is a checksum-style verification of the collider, simply returning the - * total number of edge-face bounding box overlaps between this and other. - * - * @param other A Manifold to overlap with. - */ -int Manifold::NumOverlaps(const Manifold& other) const { - SparseIndices overlaps = GetCsgLeafNode().GetImpl()->EdgeCollisions( - *other.GetCsgLeafNode().GetImpl()); - int num_overlaps = overlaps.size(); - - overlaps = other.GetCsgLeafNode().GetImpl()->EdgeCollisions( - *GetCsgLeafNode().GetImpl()); - return num_overlaps += overlaps.size(); -} - -/** - * Move this Manifold in space. This operation can be chained. Transforms are - * combined and applied lazily. - * - * @param v The vector to add to every vertex. - */ -Manifold Manifold::Translate(glm::vec3 v) const { - return Manifold(pNode_->Translate(v)); -} - -/** - * Scale this Manifold in space. This operation can be chained. Transforms are - * combined and applied lazily. - * - * @param v The vector to multiply every vertex by per component. - */ -Manifold Manifold::Scale(glm::vec3 v) const { - return Manifold(pNode_->Scale(v)); -} - -/** - * Applies an Euler angle rotation to the manifold, first about the X axis, then - * Y, then Z, in degrees. We use degrees so that we can minimize rounding error, - * and eliminate it completely for any multiples of 90 degrees. Additionally, - * more efficient code paths are used to update the manifold when the transforms - * only rotate by multiples of 90 degrees. This operation can be chained. - * Transforms are combined and applied lazily. - * - * @param xDegrees First rotation, degrees about the X-axis. - * @param yDegrees Second rotation, degrees about the Y-axis. - * @param zDegrees Third rotation, degrees about the Z-axis. - */ -Manifold Manifold::Rotate(float xDegrees, float yDegrees, - float zDegrees) const { - return Manifold(pNode_->Rotate(xDegrees, yDegrees, zDegrees)); -} - -/** - * Transform this Manifold in space. The first three columns form a 3x3 matrix - * transform and the last is a translation vector. This operation can be - * chained. Transforms are combined and applied lazily. - * - * @param m The affine transform matrix to apply to all the vertices. - */ -Manifold Manifold::Transform(const glm::mat4x3& m) const { - return Manifold(pNode_->Transform(m)); -} - -/** - * This function does not change the topology, but allows the vertices to be - * moved according to any arbitrary input function. It is easy to create a - * function that warps a geometrically valid object into one which overlaps, but - * that is not checked here, so it is up to the user to choose their function - * with discretion. - * - * @param warpFunc A function that modifies a given vertex position. - */ -Manifold Manifold::Warp(std::function warpFunc) const { - auto pImpl = std::make_shared(*GetCsgLeafNode().GetImpl()); - thrust::for_each_n(thrust::host, pImpl->vertPos_.begin(), NumVert(), - warpFunc); - pImpl->Update(); - pImpl->faceNormal_.resize(0); // force recalculation of triNormal - pImpl->CalculateNormals(); - pImpl->SetPrecision(); - return Manifold(std::make_shared(pImpl)); -} - -/** - * Increase the density of the mesh by splitting every edge into n pieces. For - * instance, with n = 2, each triangle will be split into 4 triangles. These - * will all be coplanar (and will not be immediately collapsed) unless the - * Mesh/Manifold has halfedgeTangents specified (e.g. from the Smooth() - * constructor), in which case the new vertices will be moved to the - * interpolated surface according to their barycentric coordinates. - * - * @param n The number of pieces to split every edge into. Must be > 1. - */ -Manifold Manifold::Refine(int n) const { - auto pImpl = std::make_shared(*GetCsgLeafNode().GetImpl()); - pImpl->Refine(n); - return Manifold(std::make_shared(pImpl)); -} - -/** - * The central operation of this library: the Boolean combines two manifolds - * into another by calculating their intersections and removing the unused - * portions. - * [ε-valid](https://github.com/elalish/manifold/wiki/Manifold-Library#definition-of-%CE%B5-valid) - * inputs will produce ε-valid output. ε-invalid input may fail - * triangulation. - * - * These operations are optimized to produce nearly-instant results if either - * input is empty or their bounding boxes do not overlap. - * - * @param second The other Manifold. - * @param op The type of operation to perform. - */ -Manifold Manifold::Boolean(const Manifold& second, OpType op) const { - std::vector> children({pNode_, second.pNode_}); - return Manifold(std::make_shared(children, op)); -} - -Manifold Manifold::BatchBoolean(const std::vector& manifolds, - OpType op) { - if (manifolds.size() == 0) - return Manifold(); - else if (manifolds.size() == 1) - return manifolds[0]; - std::vector> children; - children.reserve(manifolds.size()); - for (const auto& m : manifolds) children.push_back(m.pNode_); - return Manifold(std::make_shared(children, op)); -} - -/** - * Shorthand for Boolean Union. - */ -Manifold Manifold::operator+(const Manifold& Q) const { - return Boolean(Q, OpType::ADD); -} - -/** - * Shorthand for Boolean Union assignment. - */ -Manifold& Manifold::operator+=(const Manifold& Q) { - *this = *this + Q; - return *this; -} - -/** - * Shorthand for Boolean Difference. - */ -Manifold Manifold::operator-(const Manifold& Q) const { - return Boolean(Q, OpType::SUBTRACT); -} - -/** - * Shorthand for Boolean Difference assignment. - */ -Manifold& Manifold::operator-=(const Manifold& Q) { - *this = *this - Q; - return *this; -} - -/** - * Shorthand for Boolean Intersection. - */ -Manifold Manifold::operator^(const Manifold& Q) const { - return Boolean(Q, OpType::INTERSECT); -} - -/** - * Shorthand for Boolean Intersection assignment. - */ -Manifold& Manifold::operator^=(const Manifold& Q) { - *this = *this ^ Q; - return *this; -} - -/** - * Split cuts this manifold in two using the cutter manifold. The first result - * is the intersection, second is the difference. This is more efficient than - * doing them separately. - * - * @param cutter - */ -std::pair Manifold::Split(const Manifold& cutter) const { - auto impl1 = GetCsgLeafNode().GetImpl(); - auto impl2 = cutter.GetCsgLeafNode().GetImpl(); - - Boolean3 boolean(*impl1, *impl2, OpType::SUBTRACT); - auto result1 = std::make_shared( - std::make_unique(boolean.Result(OpType::INTERSECT))); - auto result2 = std::make_shared( - std::make_unique(boolean.Result(OpType::SUBTRACT))); - return std::make_pair(Manifold(result1), Manifold(result2)); -} - -/** - * Convenient version of Split() for a half-space. - * - * @param normal This vector is normal to the cutting plane and its length does - * not matter. The first result is in the direction of this vector, the second - * result is on the opposite side. - * @param originOffset The distance of the plane from the origin in the - * direction of the normal vector. - */ -std::pair Manifold::SplitByPlane(glm::vec3 normal, - float originOffset) const { - return Split(Halfspace(BoundingBox(), normal, originOffset)); -} - -/** - * Identical to SplitByPlane(), but calculating and returning only the first - * result. - * - * @param normal This vector is normal to the cutting plane and its length does - * not matter. The result is in the direction of this vector from the plane. - * @param originOffset The distance of the plane from the origin in the - * direction of the normal vector. - */ -Manifold Manifold::TrimByPlane(glm::vec3 normal, float originOffset) const { - return *this ^ Halfspace(BoundingBox(), normal, originOffset); -} - -ExecutionParams& ManifoldParams() { return params; } -} // namespace manifold diff --git a/IfcPlusPlus/src/external/manifold/src/manifold/src/properties.cpp b/IfcPlusPlus/src/external/manifold/src/manifold/src/properties.cpp deleted file mode 100644 index 3560bdcb8..000000000 --- a/IfcPlusPlus/src/external/manifold/src/manifold/src/properties.cpp +++ /dev/null @@ -1,373 +0,0 @@ -// Copyright 2021 The Manifold Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include -#include - -#include - -#include "impl.h" -#include "par.h" - -namespace { -using namespace manifold; - -struct FaceAreaVolume { - const Halfedge* halfedges; - const glm::vec3* vertPos; - const float precision; - - __host__ __device__ thrust::pair operator()(int face) { - float perimeter = 0; - glm::vec3 edge[3]; - for (int i : {0, 1, 2}) { - const int j = (i + 1) % 3; - edge[i] = vertPos[halfedges[3 * face + j].startVert] - - vertPos[halfedges[3 * face + i].startVert]; - perimeter += glm::length(edge[i]); - } - glm::vec3 crossP = glm::cross(edge[0], edge[1]); - - float area = glm::length(crossP); - float volume = glm::dot(crossP, vertPos[halfedges[3 * face].startVert]); - - return area > perimeter * precision - ? thrust::make_pair(area / 2.0f, volume / 6.0f) - : thrust::make_pair(0.0f, 0.0f); - } -}; - -struct PosMin - : public thrust::binary_function { - __host__ __device__ glm::vec3 operator()(glm::vec3 a, glm::vec3 b) { - if (isnan(a.x)) return b; - if (isnan(b.x)) return a; - return glm::min(a, b); - } -}; - -struct PosMax - : public thrust::binary_function { - __host__ __device__ glm::vec3 operator()(glm::vec3 a, glm::vec3 b) { - if (isnan(a.x)) return b; - if (isnan(b.x)) return a; - return glm::max(a, b); - } -}; - -struct FiniteVert { - __host__ __device__ bool operator()(glm::vec3 v) { - return glm::all(glm::isfinite(v)); - } -}; - -struct MakeMinMax { - __host__ __device__ glm::ivec2 operator()(glm::ivec3 tri) { - return glm::ivec2(glm::min(tri[0], glm::min(tri[1], tri[2])), - glm::max(tri[0], glm::max(tri[1], tri[2]))); - } -}; - -struct MinMax - : public thrust::binary_function { - __host__ __device__ glm::ivec2 operator()(glm::ivec2 a, glm::ivec2 b) { - a[0] = glm::min(a[0], b[0]); - a[1] = glm::max(a[1], b[1]); - return a; - } -}; - -struct SumPair : public thrust::binary_function, - thrust::pair, - thrust::pair> { - __host__ __device__ thrust::pair operator()( - thrust::pair a, thrust::pair b) { - a.first += b.first; - a.second += b.second; - return a; - } -}; - -struct CurvatureAngles { - float* meanCurvature; - float* gaussianCurvature; - float* area; - float* degree; - const Halfedge* halfedge; - const glm::vec3* vertPos; - const glm::vec3* triNormal; - - __host__ __device__ void operator()(int tri) { - glm::vec3 edge[3]; - glm::vec3 edgeLength(0.0); - for (int i : {0, 1, 2}) { - const int startVert = halfedge[3 * tri + i].startVert; - const int endVert = halfedge[3 * tri + i].endVert; - edge[i] = vertPos[endVert] - vertPos[startVert]; - edgeLength[i] = glm::length(edge[i]); - edge[i] /= edgeLength[i]; - const int neighborTri = halfedge[3 * tri + i].pairedHalfedge / 3; - const float dihedral = - 0.25 * edgeLength[i] * - glm::asin(glm::dot(glm::cross(triNormal[tri], triNormal[neighborTri]), - edge[i])); - AtomicAdd(meanCurvature[startVert], dihedral); - AtomicAdd(meanCurvature[endVert], dihedral); - AtomicAdd(degree[startVert], 1.0f); - } - - glm::vec3 phi; - phi[0] = glm::acos(-glm::dot(edge[2], edge[0])); - phi[1] = glm::acos(-glm::dot(edge[0], edge[1])); - phi[2] = glm::pi() - phi[0] - phi[1]; - const float area3 = edgeLength[0] * edgeLength[1] * - glm::length(glm::cross(edge[0], edge[1])) / 6; - - for (int i : {0, 1, 2}) { - const int vert = halfedge[3 * tri + i].startVert; - AtomicAdd(gaussianCurvature[vert], -phi[i]); - AtomicAdd(area[vert], area3); - } - } -}; - -struct NormalizeCurvature { - __host__ __device__ void operator()( - thrust::tuple inOut) { - float& meanCurvature = thrust::get<0>(inOut); - float& gaussianCurvature = thrust::get<1>(inOut); - float area = thrust::get<2>(inOut); - float degree = thrust::get<3>(inOut); - float factor = degree / (6 * area); - meanCurvature *= factor; - gaussianCurvature *= factor; - } -}; - -struct CheckManifold { - const Halfedge* halfedges; - - __host__ __device__ bool operator()(int edge) { - const Halfedge halfedge = halfedges[edge]; - if (halfedge.startVert == -1 && halfedge.endVert == -1 && - halfedge.pairedHalfedge == -1) - return true; - - const Halfedge paired = halfedges[halfedge.pairedHalfedge]; - bool good = true; - good &= paired.pairedHalfedge == edge; - good &= halfedge.startVert != halfedge.endVert; - good &= halfedge.startVert == paired.endVert; - good &= halfedge.endVert == paired.startVert; - return good; - } -}; - -struct NoDuplicates { - const Halfedge* halfedges; - - __host__ __device__ bool operator()(int edge) { - const Halfedge halfedge = halfedges[edge]; - if (halfedge.startVert == -1 && halfedge.endVert == -1 && - halfedge.pairedHalfedge == -1) - return true; - return halfedge.startVert != halfedges[edge + 1].startVert || - halfedge.endVert != halfedges[edge + 1].endVert; - } -}; - -struct CheckCCW { - const Halfedge* halfedges; - const glm::vec3* vertPos; - const glm::vec3* triNormal; - const float tol; - - __host__ __device__ bool operator()(int face) { - if (halfedges[3 * face].pairedHalfedge < 0) return true; - - const glm::mat3x2 projection = GetAxisAlignedProjection(triNormal[face]); - glm::vec2 v[3]; - for (int i : {0, 1, 2}) - v[i] = projection * vertPos[halfedges[3 * face + i].startVert]; - - int ccw = CCW(v[0], v[1], v[2], glm::abs(tol)); - bool check = tol > 0 ? ccw >= 0 : ccw == 0; - -#ifdef MANIFOLD_DEBUG - if (tol > 0 && !check) { - glm::vec2 v1 = v[1] - v[0]; - glm::vec2 v2 = v[2] - v[0]; - float area = v1.x * v2.y - v1.y * v2.x; - float base2 = glm::max(glm::dot(v1, v1), glm::dot(v2, v2)); - float base = glm::sqrt(base2); - glm::vec3 V0 = vertPos[halfedges[3 * face].startVert]; - glm::vec3 V1 = vertPos[halfedges[3 * face + 1].startVert]; - glm::vec3 V2 = vertPos[halfedges[3 * face + 2].startVert]; - glm::vec3 norm = glm::cross(V1 - V0, V2 - V0); - printf( - "Tri %d does not match normal, approx height = %g, base = %g\n" - "tol = %g, area2 = %g, base2*tol2 = %g\n" - "normal = %g, %g, %g\n" - "norm = %g, %g, %g\nverts: %d, %d, %d\n", - face, area / base, base, tol, area * area, base2 * tol * tol, - triNormal[face].x, triNormal[face].y, triNormal[face].z, norm.x, - norm.y, norm.z, halfedges[3 * face].startVert, - halfedges[3 * face + 1].startVert, halfedges[3 * face + 2].startVert); - } -#endif - return check; - } -}; -} // namespace - -namespace manifold { - -/** - * Returns true if this manifold is in fact an oriented even manifold and all of - * the data structures are consistent. - */ -bool Manifold::Impl::IsManifold() const { - if (halfedge_.size() == 0) return true; - auto policy = autoPolicy(halfedge_.size()); - - return all_of(policy, countAt(0), countAt(halfedge_.size()), - CheckManifold({halfedge_.cptrD()})); -} - -/** - * Returns true if this manifold is in fact an oriented 2-manifold and all of - * the data structures are consistent. - */ -bool Manifold::Impl::Is2Manifold() const { - if (halfedge_.size() == 0) return true; - auto policy = autoPolicy(halfedge_.size()); - - if (!IsManifold()) return false; - - VecDH halfedge(halfedge_); - sort(policy, halfedge.begin(), halfedge.end()); - - return all_of(policy, countAt(0), countAt(2 * NumEdge() - 1), - NoDuplicates({halfedge.cptrD()})); -} - -/** - * Returns true if all triangles are CCW relative to their triNormals_. - */ -bool Manifold::Impl::MatchesTriNormals() const { - if (halfedge_.size() == 0 || faceNormal_.size() != NumTri()) return true; - return all_of(autoPolicy(NumTri()), countAt(0), countAt(NumTri()), - CheckCCW({halfedge_.cptrD(), vertPos_.cptrD(), - faceNormal_.cptrD(), 2 * precision_})); -} - -/** - * Returns the number of triangles that are colinear within precision_. - */ -int Manifold::Impl::NumDegenerateTris() const { - if (halfedge_.size() == 0 || faceNormal_.size() != NumTri()) return true; - return count_if(autoPolicy(NumTri()), countAt(0), countAt(NumTri()), - CheckCCW({halfedge_.cptrD(), vertPos_.cptrD(), - faceNormal_.cptrD(), -1 * precision_ / 2})); -} - -Properties Manifold::Impl::GetProperties() const { - if (IsEmpty()) return {0, 0}; - auto areaVolume = transform_reduce>( - autoPolicy(NumTri()), countAt(0), countAt(NumTri()), - FaceAreaVolume({halfedge_.cptrD(), vertPos_.cptrD(), precision_}), - thrust::make_pair(0.0f, 0.0f), SumPair()); - return {areaVolume.first, areaVolume.second}; -} - -Curvature Manifold::Impl::GetCurvature() const { - Curvature result; - if (IsEmpty()) return result; - VecDH vertMeanCurvature(NumVert(), 0); - VecDH vertGaussianCurvature(NumVert(), glm::two_pi()); - VecDH vertArea(NumVert(), 0); - VecDH degree(NumVert(), 0); - auto policy = autoPolicy(NumTri()); - for_each( - policy, countAt(0), countAt(NumTri()), - CurvatureAngles({vertMeanCurvature.ptrD(), vertGaussianCurvature.ptrD(), - vertArea.ptrD(), degree.ptrD(), halfedge_.cptrD(), - vertPos_.cptrD(), faceNormal_.cptrD()})); - for_each_n(policy, - zip(vertMeanCurvature.begin(), vertGaussianCurvature.begin(), - vertArea.begin(), degree.begin()), - NumVert(), NormalizeCurvature()); - result.minMeanCurvature = reduce( - policy, vertMeanCurvature.begin(), vertMeanCurvature.end(), - std::numeric_limits::infinity(), thrust::minimum()); - result.maxMeanCurvature = reduce( - policy, vertMeanCurvature.begin(), vertMeanCurvature.end(), - -std::numeric_limits::infinity(), thrust::maximum()); - result.minGaussianCurvature = reduce( - policy, vertGaussianCurvature.begin(), vertGaussianCurvature.end(), - std::numeric_limits::infinity(), thrust::minimum()); - result.maxGaussianCurvature = reduce( - policy, vertGaussianCurvature.begin(), vertGaussianCurvature.end(), - -std::numeric_limits::infinity(), thrust::maximum()); - result.vertMeanCurvature.insert(result.vertMeanCurvature.end(), - vertMeanCurvature.begin(), - vertMeanCurvature.end()); - result.vertGaussianCurvature.insert(result.vertGaussianCurvature.end(), - vertGaussianCurvature.begin(), - vertGaussianCurvature.end()); - return result; -} - -/** - * Calculates the bounding box of the entire manifold, which is stored - * internally to short-cut Boolean operations and to serve as the precision - * range for Morton code calculation. Ignores NaNs. - */ -void Manifold::Impl::CalculateBBox() { - auto policy = autoPolicy(NumVert()); - bBox_.min = reduce( - policy, vertPos_.begin(), vertPos_.end(), - glm::vec3(std::numeric_limits::infinity()), PosMin()); - bBox_.max = reduce( - policy, vertPos_.begin(), vertPos_.end(), - glm::vec3(-std::numeric_limits::infinity()), PosMax()); -} - -/** - * Determines if all verts are finite. Checking just the bounding box dimensions - * is insufficient as it ignores NaNs. - */ -bool Manifold::Impl::IsFinite() const { - auto policy = autoPolicy(NumVert()); - return transform_reduce(policy, vertPos_.begin(), vertPos_.end(), - FiniteVert(), true, - thrust::logical_and()); -} - -/** - * Checks that the input triVerts array has all indices inside bounds of the - * vertPos_ array. - */ -bool Manifold::Impl::IsIndexInBounds(const VecDH& triVerts) const { - auto policy = autoPolicy(triVerts.size()); - glm::ivec2 minmax = transform_reduce( - policy, triVerts.begin(), triVerts.end(), MakeMinMax(), - glm::ivec2(std::numeric_limits::max(), - std::numeric_limits::min()), - MinMax()); - - return minmax[0] >= 0 && minmax[1] < NumVert(); -} -} // namespace manifold diff --git a/IfcPlusPlus/src/external/manifold/src/manifold/src/shared.h b/IfcPlusPlus/src/external/manifold/src/manifold/src/shared.h deleted file mode 100644 index bf774b192..000000000 --- a/IfcPlusPlus/src/external/manifold/src/manifold/src/shared.h +++ /dev/null @@ -1,195 +0,0 @@ -// Copyright 2021 The Manifold Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include "par.h" -#include "utils.h" -#include "vec_dh.h" - -namespace manifold { - -/** @addtogroup Private - * @{ - */ -__host__ __device__ inline glm::vec3 SafeNormalize(glm::vec3 v) { - v = glm::normalize(v); - return glm::isfinite(v.x) ? v : glm::vec3(0); -} - -__host__ __device__ inline int NextHalfedge(int current) { - ++current; - if (current % 3 == 0) current -= 3; - return current; -} - -__host__ __device__ inline glm::vec3 UVW(int vert, - const glm::vec3* barycentric) { - glm::vec3 uvw(0.0f); - if (vert < 0) { - uvw[vert + 3] = 1; - } else { - uvw = barycentric[vert]; - } - return uvw; -} - -/** - * By using the closest axis-aligned projection to the normal instead of a - * projection along the normal, we avoid introducing any rounding error. - */ -__host__ __device__ inline glm::mat3x2 GetAxisAlignedProjection( - glm::vec3 normal) { - glm::vec3 absNormal = glm::abs(normal); - float xyzMax; - glm::mat2x3 projection; - if (absNormal.z > absNormal.x && absNormal.z > absNormal.y) { - projection = glm::mat2x3(1.0f, 0.0f, 0.0f, // - 0.0f, 1.0f, 0.0f); - xyzMax = normal.z; - } else if (absNormal.y > absNormal.x) { - projection = glm::mat2x3(0.0f, 0.0f, 1.0f, // - 1.0f, 0.0f, 0.0f); - xyzMax = normal.y; - } else { - projection = glm::mat2x3(0.0f, 1.0f, 0.0f, // - 0.0f, 0.0f, 1.0f); - xyzMax = normal.x; - } - if (xyzMax < 0) projection[0] *= -1.0f; - return glm::transpose(projection); -} - -__host__ __device__ inline glm::vec3 GetBarycentric(const glm::vec3& v, - const glm::mat3& triPos, - float precision) { - const glm::mat3 edges(triPos[2] - triPos[1], triPos[0] - triPos[2], - triPos[1] - triPos[0]); - const glm::vec3 d2(glm::dot(edges[0], edges[0]), glm::dot(edges[1], edges[1]), - glm::dot(edges[2], edges[2])); - int longside = d2[0] > d2[1] && d2[0] > d2[2] ? 0 : d2[1] > d2[2] ? 1 : 2; - const glm::vec3 crossP = glm::cross(edges[0], edges[1]); - const float area2 = glm::dot(crossP, crossP); - const float tol2 = precision * precision; - const float vol = glm::dot(crossP, v - triPos[2]); - if (vol * vol > area2 * tol2) return glm::vec3(NAN); - - if (d2[longside] < tol2) { // point - return glm::vec3(1, 0, 0); - } else if (area2 > d2[longside] * tol2) { // triangle - glm::vec3 uvw(0); - for (int i : {0, 1, 2}) { - int j = i + 1; - if (j > 2) j -= 3; - uvw[i] = glm::dot(glm::cross(edges[i], v - triPos[j]), crossP); - } - uvw /= (uvw[0] + uvw[1] + uvw[2]); - return uvw; - } else { // line - int nextside = longside + 1; - if (nextside > 2) nextside -= 3; - const float alpha = - glm::dot(v - triPos[nextside], edges[longside]) / d2[longside]; - glm::vec3 uvw(0); - uvw[longside] = 0; - uvw[nextside++] = 1 - alpha; - if (nextside > 2) nextside -= 3; - uvw[nextside] = alpha; - return uvw; - } -} - -/** - * The fundamental component of the halfedge data structure used for storing and - * operating on the Manifold. - */ -struct Halfedge { - int startVert, endVert; - int pairedHalfedge; - int face; - __host__ __device__ bool IsForward() const { return startVert < endVert; } - __host__ __device__ bool operator<(const Halfedge& other) const { - return startVert == other.startVert ? endVert < other.endVert - : startVert < other.startVert; - } -}; - -/** - * This is a temporary edge structure which only stores edges forward and - * references the halfedge it was created from. - */ -struct TmpEdge { - int first, second, halfedgeIdx; - - __host__ __device__ TmpEdge() {} - __host__ __device__ TmpEdge(int start, int end, int idx) { - first = glm::min(start, end); - second = glm::max(start, end); - halfedgeIdx = idx; - } - - __host__ __device__ bool operator<(const TmpEdge& other) const { - return first == other.first ? second < other.second : first < other.first; - } -}; -/** @} */ - -struct Halfedge2Tmp { - __host__ __device__ void operator()( - thrust::tuple inout) { - const Halfedge& halfedge = thrust::get<1>(inout); - int idx = thrust::get<2>(inout); - if (!halfedge.IsForward()) idx = -1; - - thrust::get<0>(inout) = TmpEdge(halfedge.startVert, halfedge.endVert, idx); - } -}; - -struct TmpInvalid { - __host__ __device__ bool operator()(const TmpEdge& edge) { - return edge.halfedgeIdx < 0; - } -}; - -VecDH inline CreateTmpEdges(const VecDH& halfedge) { - VecDH edges(halfedge.size()); - for_each_n(autoPolicy(edges.size()), - zip(edges.begin(), halfedge.begin(), countAt(0)), edges.size(), - Halfedge2Tmp()); - int numEdge = - remove_if( - autoPolicy(edges.size()), edges.begin(), edges.end(), TmpInvalid()) - - edges.begin(); - ASSERT(numEdge == halfedge.size() / 2, topologyErr, "Not oriented!"); - edges.resize(numEdge); - return edges; -} - -struct ReindexEdge { - const TmpEdge* edges; - - __host__ __device__ void operator()(int& edge) { - edge = edges[edge].halfedgeIdx; - } -}; - -#ifdef MANIFOLD_DEBUG -inline std::ostream& operator<<(std::ostream& stream, const Halfedge& edge) { - return stream << "startVert = " << edge.startVert - << ", endVert = " << edge.endVert - << ", pairedHalfedge = " << edge.pairedHalfedge - << ", face = " << edge.face; -} -#endif -} // namespace manifold diff --git a/IfcPlusPlus/src/external/manifold/src/manifold/src/smoothing.cpp b/IfcPlusPlus/src/external/manifold/src/manifold/src/smoothing.cpp deleted file mode 100644 index 89d1ff47c..000000000 --- a/IfcPlusPlus/src/external/manifold/src/manifold/src/smoothing.cpp +++ /dev/null @@ -1,525 +0,0 @@ -// Copyright 2021 The Manifold Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -#include "impl.h" -#include "par.h" - -namespace { -using namespace manifold; - -__host__ __device__ glm::vec3 OrthogonalTo(glm::vec3 in, glm::vec3 ref) { - in -= glm::dot(in, ref) * ref; - return in; -} - -/** - * The total number of verts if a triangle is subdivided naturally such that - * each edge has edgeVerts verts along it (edgeVerts >= -1). - */ -__host__ __device__ int VertsPerTri(int edgeVerts) { - return (edgeVerts * edgeVerts + edgeVerts) / 2; -} - -struct Barycentric { - int tri; - glm::vec3 uvw; -}; - -struct ReindexHalfedge { - int* half2Edge; - - __host__ __device__ void operator()(thrust::tuple in) { - const int edge = thrust::get<0>(in); - const int halfedge = thrust::get<1>(in).halfedgeIdx; - - half2Edge[halfedge] = edge; - } -}; - -struct EdgeVerts { - glm::vec3* vertPos; - const int startIdx; - const int n; - - __host__ __device__ void operator()(thrust::tuple in) { - int edge = thrust::get<0>(in); - TmpEdge edgeVerts = thrust::get<1>(in); - - float invTotal = 1.0f / n; - for (int i = 1; i < n; ++i) - vertPos[startIdx + (n - 1) * edge + i - 1] = - (float(n - i) * vertPos[edgeVerts.first] + - float(i) * vertPos[edgeVerts.second]) * - invTotal; - } -}; - -struct InteriorVerts { - glm::vec3* vertPos; - glm::vec3* uvw; - BaryRef* triBary; - glm::vec3* uvwNew; - BaryRef* triBaryNew; - const glm::vec3* uvwOld; - const int startIdx; - const int n; - const Halfedge* halfedge; - - __host__ __device__ void operator()(thrust::tuple in) { - const int tri = thrust::get<0>(in); - const BaryRef baryOld = thrust::get<1>(in); - - glm::mat3 uvwOldTri; - for (int i : {0, 1, 2}) uvwOldTri[i] = UVW(baryOld.vertBary[i], uvwOld); - - const float invTotal = 1.0f / n; - int posTri = tri * n * n; - int posBary = tri * VertsPerTri(n + 1); - int pos = startIdx + tri * VertsPerTri(n - 2); - for (int i = 0; i <= n; ++i) { - for (int j = 0; j <= n - i; ++j) { - const int k = n - i - j; - const float u = invTotal * j; - const float v = invTotal * k; - const float w = invTotal * i; - const int first = posBary; - uvw[posBary] = {u, v, w}; - uvwNew[posBary] = uvwOldTri * uvw[posBary]; - ++posBary; - if (j == n - i) continue; - - // The three retained verts are denoted by their index - 3. uvw entries - // are added for them out of laziness of indexing only. - const int a = (k == n) ? -2 : first; - const int b = (i == n - 1) ? -1 : first + n - i + 1; - const int c = (j == n - 1) ? -3 : first + 1; - glm::ivec3 vertBary(c, a, b); - triBary[posTri] = {-1, -1, tri, vertBary}; - triBaryNew[posTri++] = {baryOld.meshID, baryOld.originalID, baryOld.tri, - vertBary}; - if (j < n - 1 - i) { - int d = b + 1; // d cannot be a retained vert - vertBary = {b, d, c}; - triBary[posTri] = {-1, -1, tri, vertBary}; - triBaryNew[posTri++] = {baryOld.meshID, baryOld.originalID, - baryOld.tri, vertBary}; - } - - if (i == 0 || j == 0 || k == 0) continue; - - vertPos[pos++] = u * vertPos[halfedge[3 * tri].startVert] + // - v * vertPos[halfedge[3 * tri + 1].startVert] + // - w * vertPos[halfedge[3 * tri + 2].startVert]; - } - } - } -}; - -struct SplitTris { - glm::ivec3* triVerts; - const Halfedge* halfedge; - const int* half2Edge; - const int edgeIdx; - const int triIdx; - const int n; - - __host__ __device__ int EdgeVert(int i, int inHalfedge) const { - bool forward = halfedge[inHalfedge].IsForward(); - int edge = forward ? half2Edge[inHalfedge] - : half2Edge[halfedge[inHalfedge].pairedHalfedge]; - return edgeIdx + (n - 1) * edge + (forward ? i - 1 : n - 1 - i); - } - - __host__ __device__ int TriVert(int i, int j, int tri) const { - --i; - --j; - int m = n - 2; - int vertsPerTri = (m * m + m) / 2; - int vertOffset = (i * (2 * m - i + 1)) / 2 + j; - return triIdx + vertsPerTri * tri + vertOffset; - } - - __host__ __device__ int Vert(int i, int j, int tri) const { - bool edge0 = i == 0; - bool edge1 = j == 0; - bool edge2 = j == n - i; - if (edge0) { - if (edge1) - return halfedge[3 * tri + 1].startVert; - else if (edge2) - return halfedge[3 * tri].startVert; - else - return EdgeVert(n - j, 3 * tri); - } else if (edge1) { - if (edge2) - return halfedge[3 * tri + 2].startVert; - else - return EdgeVert(i, 3 * tri + 1); - } else if (edge2) - return EdgeVert(j, 3 * tri + 2); - else - return TriVert(i, j, tri); - } - - __host__ __device__ void operator()(int tri) { - int pos = n * n * tri; - for (int i = 0; i < n; ++i) { - for (int j = 0; j < n - i; ++j) { - int a = Vert(i, j, tri); - int b = Vert(i + 1, j, tri); - int c = Vert(i, j + 1, tri); - triVerts[pos++] = glm::ivec3(c, a, b); - if (j < n - 1 - i) { - int d = Vert(i + 1, j + 1, tri); - triVerts[pos++] = glm::ivec3(b, d, c); - } - } - } - } -}; - -struct SmoothBezier { - const glm::vec3* vertPos; - const glm::vec3* triNormal; - const glm::vec3* vertNormal; - const Halfedge* halfedge; - - __host__ __device__ void operator()( - thrust::tuple inOut) { - glm::vec4& tangent = thrust::get<0>(inOut); - const Halfedge edge = thrust::get<1>(inOut); - - const glm::vec3 startV = vertPos[edge.startVert]; - const glm::vec3 edgeVec = vertPos[edge.endVert] - startV; - const glm::vec3 edgeNormal = - (triNormal[edge.face] + triNormal[halfedge[edge.pairedHalfedge].face]) / - 2.0f; - glm::vec3 dir = glm::normalize(glm::cross(glm::cross(edgeNormal, edgeVec), - vertNormal[edge.startVert])); - - const float weight = glm::abs(glm::dot(dir, glm::normalize(edgeVec))); - // Quadratic weighted bezier for circular interpolation - const glm::vec4 bz2 = - weight * - glm::vec4(startV + dir * glm::length(edgeVec) / (2 * weight), 1.0f); - // Equivalent cubic weighted bezier - const glm::vec4 bz3 = glm::mix(glm::vec4(startV, 1.0f), bz2, 2 / 3.0f); - // Convert from homogeneous form to geometric form - tangent = glm::vec4(glm::vec3(bz3) / bz3.w - startV, bz3.w); - } -}; - -struct TriBary2Vert { - Barycentric* vertBary; - int* lock; - const glm::vec3* uvw; - const Halfedge* halfedge; - - __host__ __device__ void operator()(thrust::tuple in) { - const BaryRef baryRef = thrust::get<0>(in); - const int tri = thrust::get<1>(in); - - for (int i : {0, 1, 2}) { - int vert = halfedge[3 * tri + i].startVert; - if (AtomicAdd(lock[vert], 1) != 0) continue; - vertBary[vert] = {baryRef.tri, UVW(baryRef.vertBary[i], uvw)}; - } - } -}; - -struct InterpTri { - const Halfedge* halfedge; - const glm::vec4* halfedgeTangent; - const glm::vec3* vertPos; - - __host__ __device__ glm::vec4 Homogeneous(glm::vec4 v) const { - v.x *= v.w; - v.y *= v.w; - v.z *= v.w; - return v; - } - - __host__ __device__ glm::vec4 Homogeneous(glm::vec3 v) const { - return glm::vec4(v, 1.0f); - } - - __host__ __device__ glm::vec3 HNormalize(glm::vec4 v) const { - return glm::vec3(v) / v.w; - } - - __host__ __device__ glm::vec4 Bezier(glm::vec3 point, - glm::vec4 tangent) const { - return Homogeneous(glm::vec4(point, 0) + tangent); - } - - __host__ __device__ glm::mat2x4 CubicBezier2Linear(glm::vec4 p0, glm::vec4 p1, - glm::vec4 p2, glm::vec4 p3, - float x) const { - glm::mat2x4 out; - glm::vec4 p12 = glm::mix(p1, p2, x); - out[0] = glm::mix(glm::mix(p0, p1, x), p12, x); - out[1] = glm::mix(p12, glm::mix(p2, p3, x), x); - return out; - } - - __host__ __device__ glm::vec3 BezierPoint(glm::mat2x4 points, float x) const { - return HNormalize(glm::mix(points[0], points[1], x)); - } - - __host__ __device__ glm::vec3 BezierTangent(glm::mat2x4 points) const { - return glm::normalize(HNormalize(points[1]) - HNormalize(points[0])); - } - - __host__ __device__ void operator()( - thrust::tuple inOut) { - glm::vec3& pos = thrust::get<0>(inOut); - const int tri = thrust::get<1>(inOut).tri; - const glm::vec3 uvw = thrust::get<1>(inOut).uvw; - - glm::vec4 posH(0); - const glm::mat3 corners = {vertPos[halfedge[3 * tri].startVert], - vertPos[halfedge[3 * tri + 1].startVert], - vertPos[halfedge[3 * tri + 2].startVert]}; - - for (const int i : {0, 1, 2}) { - if (uvw[i] == 1) { - pos = glm::vec3(corners[i]); - return; - } - } - - const glm::mat3x4 tangentR = {halfedgeTangent[3 * tri], - halfedgeTangent[3 * tri + 1], - halfedgeTangent[3 * tri + 2]}; - const glm::mat3x4 tangentL = { - halfedgeTangent[halfedge[3 * tri + 2].pairedHalfedge], - halfedgeTangent[halfedge[3 * tri].pairedHalfedge], - halfedgeTangent[halfedge[3 * tri + 1].pairedHalfedge]}; - - for (const int i : {0, 1, 2}) { - const int j = (i + 1) % 3; - const int k = (i + 2) % 3; - const float x = uvw[k] / (1 - uvw[i]); - - const glm::mat2x4 bez = CubicBezier2Linear( - Homogeneous(corners[j]), Bezier(corners[j], tangentR[j]), - Bezier(corners[k], tangentL[k]), Homogeneous(corners[k]), x); - const glm::vec3 end = BezierPoint(bez, x); - const glm::vec3 tangent = BezierTangent(bez); - - const glm::vec3 jBitangent = SafeNormalize(OrthogonalTo( - glm::vec3(tangentL[j]), SafeNormalize(glm::vec3(tangentR[j])))); - const glm::vec3 kBitangent = SafeNormalize(OrthogonalTo( - glm::vec3(tangentR[k]), -SafeNormalize(glm::vec3(tangentL[k])))); - const glm::vec3 normal = SafeNormalize( - glm::cross(glm::mix(jBitangent, kBitangent, x), tangent)); - const glm::vec3 delta = OrthogonalTo( - glm::mix(glm::vec3(tangentL[j]), glm::vec3(tangentR[k]), x), normal); - const float deltaW = glm::mix(tangentL[j].w, tangentR[k].w, x); - - const glm::mat2x4 bez1 = CubicBezier2Linear( - Homogeneous(end), Homogeneous(glm::vec4(end + delta, deltaW)), - Bezier(corners[i], glm::mix(tangentR[i], tangentL[i], x)), - Homogeneous(corners[i]), uvw[i]); - const glm::vec3 p = BezierPoint(bez1, uvw[i]); - float w = uvw[j] * uvw[j] * uvw[k] * uvw[k]; - posH += Homogeneous(glm::vec4(p, w)); - } - pos = HNormalize(posH); - } -}; -} // namespace - -namespace manifold { - -/** - * Calculates halfedgeTangent_, allowing the manifold to be refined and - * smoothed. The tangents form weighted cubic Beziers along each edge. This - * function creates circular arcs where possible (minimizing maximum curvature), - * constrained to the vertex normals. Where sharpenedEdges are specified, the - * tangents are shortened that intersect the sharpened edge, concentrating the - * curvature there, while the tangents of the sharp edges themselves are aligned - * for continuity. - */ -void Manifold::Impl::CreateTangents( - const std::vector& sharpenedEdges) { - const int numHalfedge = halfedge_.size(); - halfedgeTangent_.resize(numHalfedge); - - for_each_n(autoPolicy(numHalfedge), - zip(halfedgeTangent_.begin(), halfedge_.cbegin()), numHalfedge, - SmoothBezier({vertPos_.cptrD(), faceNormal_.cptrD(), - vertNormal_.cptrD(), halfedge_.cptrD()})); - - if (!sharpenedEdges.empty()) { - const VecDH& triBary = meshRelation_.triBary; - - // sharpenedEdges are referenced to the input Mesh, but the triangles have - // been sorted in creating the Manifold, so the indices are converted using - // meshRelation_. - std::vector oldHalfedge2New(halfedge_.size()); - for (int tri = 0; tri < NumTri(); ++tri) { - int oldTri = triBary[tri].tri; - for (int i : {0, 1, 2}) oldHalfedge2New[3 * oldTri + i] = 3 * tri + i; - } - - using Pair = std::pair; - // Fill in missing pairs with default smoothness = 1. - std::map edges; - for (Smoothness edge : sharpenedEdges) { - if (edge.smoothness == 1) continue; - edge.halfedge = oldHalfedge2New[edge.halfedge]; - int pair = halfedge_[edge.halfedge].pairedHalfedge; - if (edges.find(pair) == edges.end()) { - edges[edge.halfedge] = {edge, {pair, 1}}; - } else { - edges[pair].second = edge; - } - } - - std::map> vertTangents; - for (const auto& value : edges) { - const Pair edge = value.second; - vertTangents[halfedge_[edge.first.halfedge].startVert].push_back(edge); - vertTangents[halfedge_[edge.second.halfedge].startVert].push_back( - {edge.second, edge.first}); - } - - VecDH& tangent = halfedgeTangent_; - for (const auto& value : vertTangents) { - const std::vector& vert = value.second; - // Sharp edges that end are smooth at their terminal vert. - if (vert.size() == 1) continue; - if (vert.size() == 2) { // Make continuous edge - const int first = vert[0].first.halfedge; - const int second = vert[1].first.halfedge; - const glm::vec3 newTangent = glm::normalize(glm::vec3(tangent[first]) - - glm::vec3(tangent[second])); - tangent[first] = - glm::vec4(glm::length(glm::vec3(tangent[first])) * newTangent, - tangent[first].w); - tangent[second] = - glm::vec4(-glm::length(glm::vec3(tangent[second])) * newTangent, - tangent[second].w); - - auto SmoothHalf = [&](int first, int last, float smoothness) { - int current = NextHalfedge(halfedge_[first].pairedHalfedge); - while (current != last) { - const float cosBeta = glm::dot( - newTangent, glm::normalize(glm::vec3(tangent[current]))); - const float factor = - (1 - smoothness) * cosBeta * cosBeta + smoothness; - tangent[current] = glm::vec4(factor * glm::vec3(tangent[current]), - tangent[current].w); - current = NextHalfedge(halfedge_[current].pairedHalfedge); - } - }; - - SmoothHalf(first, second, - (vert[0].second.smoothness + vert[1].first.smoothness) / 2); - SmoothHalf(second, first, - (vert[1].second.smoothness + vert[0].first.smoothness) / 2); - - } else { // Sharpen vertex uniformly - float smoothness = 0; - for (const Pair& pair : vert) { - smoothness += pair.first.smoothness; - smoothness += pair.second.smoothness; - } - smoothness /= 2 * vert.size(); - - const int start = vert[0].first.halfedge; - int current = start; - do { - tangent[current] = glm::vec4(smoothness * glm::vec3(tangent[current]), - tangent[current].w); - current = NextHalfedge(halfedge_[current].pairedHalfedge); - } while (current != start); - } - } - } -} - -/** - * Split each edge into n pieces and sub-triangulate each triangle accordingly. - * This function doesn't run Finish(), as that is expensive and it'll need to be - * run after the new vertices have moved, which is a likely scenario after - * refinement (smoothing). - */ -Manifold::Impl::MeshRelationD Manifold::Impl::Subdivide(int n) { - if (n < 2) return meshRelation_; - faceNormal_.resize(0); - vertNormal_.resize(0); - int numVert = NumVert(); - int numEdge = NumEdge(); - int numTri = NumTri(); - // Append new verts - int vertsPerEdge = n - 1; - int triVertStart = numVert + numEdge * vertsPerEdge; - vertPos_.resize(triVertStart + numTri * VertsPerTri(n - 2)); - - MeshRelationD relation; - relation.barycentric.resize(numTri * VertsPerTri(n + 1)); - relation.triBary.resize(n * n * numTri); - MeshRelationD oldMeshRelation = std::move(meshRelation_); - meshRelation_.barycentric.resize(relation.barycentric.size()); - meshRelation_.triBary.resize(relation.triBary.size()); - meshRelation_.originalID = oldMeshRelation.originalID; - - VecDH edges = CreateTmpEdges(halfedge_); - VecDH half2Edge(2 * numEdge); - auto policy = autoPolicy(numEdge); - for_each_n(policy, zip(countAt(0), edges.begin()), numEdge, - ReindexHalfedge({half2Edge.ptrD()})); - for_each_n(policy, zip(countAt(0), edges.begin()), numEdge, - EdgeVerts({vertPos_.ptrD(), numVert, n})); - for_each_n( - policy, zip(countAt(0), oldMeshRelation.triBary.begin()), numTri, - InteriorVerts({vertPos_.ptrD(), relation.barycentric.ptrD(), - relation.triBary.ptrD(), meshRelation_.barycentric.ptrD(), - meshRelation_.triBary.ptrD(), - oldMeshRelation.barycentric.cptrD(), triVertStart, n, - halfedge_.ptrD()})); - // Create sub-triangles - VecDH triVerts(n * n * numTri); - for_each_n(policy, countAt(0), numTri, - SplitTris({triVerts.ptrD(), halfedge_.cptrD(), half2Edge.cptrD(), - numVert, triVertStart, n})); - CreateHalfedges(triVerts); - return relation; -} - -void Manifold::Impl::Refine(int n) { - Manifold::Impl old = *this; - MeshRelationD relation = Subdivide(n); - - if (old.halfedgeTangent_.size() == old.halfedge_.size()) { - VecDH vertBary(NumVert()); - VecDH lock(NumVert(), 0); - auto policy = autoPolicy(NumTri()); - for_each_n(policy, zip(relation.triBary.begin(), countAt(0)), NumTri(), - TriBary2Vert({vertBary.ptrD(), lock.ptrD(), - relation.barycentric.cptrD(), halfedge_.cptrD()})); - - for_each_n(policy, zip(vertPos_.begin(), vertBary.begin()), NumVert(), - InterpTri({old.halfedge_.cptrD(), old.halfedgeTangent_.cptrD(), - old.vertPos_.cptrD()})); - } - - halfedgeTangent_.resize(0); - Finish(); -} -} // namespace manifold diff --git a/IfcPlusPlus/src/external/manifold/src/manifold/src/sort.cpp b/IfcPlusPlus/src/external/manifold/src/manifold/src/sort.cpp deleted file mode 100644 index e48e01645..000000000 --- a/IfcPlusPlus/src/external/manifold/src/manifold/src/sort.cpp +++ /dev/null @@ -1,359 +0,0 @@ -// Copyright 2021 The Manifold Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -#include "impl.h" -#include "par.h" - -namespace { -using namespace manifold; - -constexpr uint32_t kNoCode = 0xFFFFFFFFu; - -struct Extrema : public thrust::binary_function { - __host__ __device__ void MakeForward(Halfedge& a) { - if (!a.IsForward()) { - int tmp = a.startVert; - a.startVert = a.endVert; - a.endVert = tmp; - } - } - - __host__ __device__ int MaxOrMinus(int a, int b) { - return glm::min(a, b) < 0 ? -1 : glm::max(a, b); - } - - __host__ __device__ Halfedge operator()(Halfedge a, Halfedge b) { - MakeForward(a); - MakeForward(b); - a.startVert = glm::min(a.startVert, b.startVert); - a.endVert = glm::max(a.endVert, b.endVert); - a.face = MaxOrMinus(a.face, b.face); - a.pairedHalfedge = MaxOrMinus(a.pairedHalfedge, b.pairedHalfedge); - return a; - } -}; - -__host__ __device__ uint32_t SpreadBits3(uint32_t v) { - v = 0xFF0000FFu & (v * 0x00010001u); - v = 0x0F00F00Fu & (v * 0x00000101u); - v = 0xC30C30C3u & (v * 0x00000011u); - v = 0x49249249u & (v * 0x00000005u); - return v; -} - -__host__ __device__ uint32_t MortonCode(glm::vec3 position, Box bBox) { - // Unreferenced vertices are marked NaN, and this will sort them to the end - // (the Morton code only uses the first 30 of 32 bits). - if (isnan(position.x)) return kNoCode; - - glm::vec3 xyz = (position - bBox.min) / (bBox.max - bBox.min); - xyz = glm::min(glm::vec3(1023.0f), glm::max(glm::vec3(0.0f), 1024.0f * xyz)); - uint32_t x = SpreadBits3(static_cast(xyz.x)); - uint32_t y = SpreadBits3(static_cast(xyz.y)); - uint32_t z = SpreadBits3(static_cast(xyz.z)); - return x * 4 + y * 2 + z; -} - -struct Morton { - const Box bBox; - - __host__ __device__ void operator()( - thrust::tuple inout) { - glm::vec3 position = thrust::get<1>(inout); - thrust::get<0>(inout) = MortonCode(position, bBox); - } -}; - -struct FaceMortonBox { - const Halfedge* halfedge; - const glm::vec3* vertPos; - const Box bBox; - - __host__ __device__ void operator()( - thrust::tuple inout) { - uint32_t& mortonCode = thrust::get<0>(inout); - Box& faceBox = thrust::get<1>(inout); - int face = thrust::get<2>(inout); - - // Removed tris are marked by all halfedges having pairedHalfedge = -1, and - // this will sort them to the end (the Morton code only uses the first 30 of - // 32 bits). - if (halfedge[3 * face].pairedHalfedge < 0) { - mortonCode = kNoCode; - return; - } - - glm::vec3 center(0.0f); - - for (const int i : {0, 1, 2}) { - const glm::vec3 pos = vertPos[halfedge[3 * face + i].startVert]; - center += pos; - faceBox.Union(pos); - } - center /= 3; - - mortonCode = MortonCode(center, bBox); - } -}; - -struct Reindex { - const int* indexInv; - - __host__ __device__ void operator()(Halfedge& edge) { - if (edge.startVert < 0) return; - edge.startVert = indexInv[edge.startVert]; - edge.endVert = indexInv[edge.endVert]; - } -}; - -template -void Permute(VecDH& inOut, const VecDH& new2Old) { - VecDH tmp(std::move(inOut)); - inOut.resize(new2Old.size()); - gather(autoPolicy(new2Old.size()), new2Old.begin(), new2Old.end(), - tmp.begin(), inOut.begin()); -} - -template void Permute(VecDH&, const VecDH&); -template void Permute(VecDH&, const VecDH&); - -struct ReindexFace { - Halfedge* halfedge; - glm::vec4* halfedgeTangent; - const Halfedge* oldHalfedge; - const glm::vec4* oldHalfedgeTangent; - const int* faceNew2Old; - const int* faceOld2New; - - __host__ __device__ void operator()(int newFace) { - const int oldFace = faceNew2Old[newFace]; - for (const int i : {0, 1, 2}) { - const int oldEdge = 3 * oldFace + i; - Halfedge edge = oldHalfedge[oldEdge]; - edge.face = newFace; - const int pairedFace = edge.pairedHalfedge / 3; - const int offset = edge.pairedHalfedge - 3 * pairedFace; - edge.pairedHalfedge = 3 * faceOld2New[pairedFace] + offset; - const int newEdge = 3 * newFace + i; - halfedge[newEdge] = edge; - if (oldHalfedgeTangent != nullptr) { - halfedgeTangent[newEdge] = oldHalfedgeTangent[oldEdge]; - } - } - } -}; - -} // namespace - -namespace manifold { - -/** - * Once halfedge_ has been filled in, this function can be called to create the - * rest of the internal data structures. This function also removes the verts - * and halfedges flagged for removal (NaN verts and -1 halfedges). - */ -void Manifold::Impl::Finish() { - if (halfedge_.size() == 0) return; - - CalculateBBox(); - SetPrecision(precision_); - if (!bBox_.IsFinite()) { - // Decimated out of existence - early out. - MarkFailure(Error::NO_ERROR); - return; - } - - SortVerts(); - VecDH faceBox; - VecDH faceMorton; - GetFaceBoxMorton(faceBox, faceMorton); - SortFaces(faceBox, faceMorton); - if (halfedge_.size() == 0) return; - - ASSERT(halfedge_.size() % 6 == 0, topologyErr, - "Not an even number of faces after sorting faces!"); - -#ifdef MANIFOLD_DEBUG - Halfedge extrema = {0, 0, 0, 0}; - extrema = reduce(autoPolicy(halfedge_.size()), halfedge_.begin(), - halfedge_.end(), extrema, Extrema()); -#endif - - ASSERT(extrema.startVert >= 0, topologyErr, "Vertex index is negative!"); - ASSERT(extrema.endVert < NumVert(), topologyErr, - "Vertex index exceeds number of verts!"); - ASSERT(extrema.face >= 0, topologyErr, "Face index is negative!"); - ASSERT(extrema.face < NumTri(), topologyErr, - "Face index exceeds number of faces!"); - ASSERT(extrema.pairedHalfedge >= 0, topologyErr, - "Halfedge index is negative!"); - ASSERT(extrema.pairedHalfedge < 2 * NumEdge(), topologyErr, - "Halfedge index exceeds number of halfedges!"); - ASSERT(meshRelation_.triBary.size() == NumTri() || - meshRelation_.triBary.size() == 0, - logicErr, "Mesh Relation doesn't fit!"); - ASSERT(faceNormal_.size() == NumTri() || faceNormal_.size() == 0, logicErr, - "faceNormal size = " + std::to_string(faceNormal_.size()) + - ", NumTri = " + std::to_string(NumTri())); - // TODO: figure out why this has a flaky failure and then enable reading - // vertNormals from a Mesh. - // ASSERT(vertNormal_.size() == NumVert() || vertNormal_.size() == 0, - // logicErr, - // "vertNormal size = " + std::to_string(vertNormal_.size()) + - // ", NumVert = " + std::to_string(NumVert())); - - CalculateNormals(); - collider_ = Collider(faceBox, faceMorton); -} - -/** - * Sorts the vertices according to their Morton code. - */ -void Manifold::Impl::SortVerts() { - const int numVert = NumVert(); - VecDH vertMorton(numVert); - auto policy = autoPolicy(numVert); - for_each_n(policy, zip(vertMorton.begin(), vertPos_.cbegin()), numVert, - Morton({bBox_})); - - VecDH vertNew2Old(numVert); - sequence(policy, vertNew2Old.begin(), vertNew2Old.end()); - sort_by_key(policy, vertMorton.begin(), vertMorton.end(), - zip(vertPos_.begin(), vertNew2Old.begin())); - - ReindexVerts(vertNew2Old, numVert); - - // Verts were flagged for removal with NaNs and assigned kNoCode to sort - // them to the end, which allows them to be removed. - const int newNumVert = - find(policy, vertMorton.begin(), - vertMorton.end(), kNoCode) - - vertMorton.begin(); - vertPos_.resize(newNumVert); - if (vertNormal_.size() == numVert) { - Permute(vertNormal_, vertNew2Old); - vertNormal_.resize(newNumVert); - } -} - -/** - * Updates the halfedges to point to new vert indices based on a mapping, - * vertNew2Old. This may be a subset, so the total number of original verts is - * also given. - */ -void Manifold::Impl::ReindexVerts(const VecDH& vertNew2Old, - int oldNumVert) { - VecDH vertOld2New(oldNumVert); - scatter(autoPolicy(oldNumVert), countAt(0), countAt(NumVert()), - vertNew2Old.begin(), vertOld2New.begin()); - for_each(autoPolicy(oldNumVert), halfedge_.begin(), halfedge_.end(), - Reindex({vertOld2New.cptrD()})); -} - -/** - * Fills the faceBox and faceMorton input with the bounding boxes and Morton - * codes of the faces, respectively. The Morton code is based on the center of - * the bounding box. - */ -void Manifold::Impl::GetFaceBoxMorton(VecDH& faceBox, - VecDH& faceMorton) const { - faceBox.resize(NumTri()); - faceMorton.resize(NumTri()); - for_each_n(autoPolicy(NumTri()), - zip(faceMorton.begin(), faceBox.begin(), countAt(0)), NumTri(), - FaceMortonBox({halfedge_.cptrD(), vertPos_.cptrD(), bBox_})); -} - -/** - * Sorts the faces of this manifold according to their input Morton code. The - * bounding box and Morton code arrays are also sorted accordingly. - */ -void Manifold::Impl::SortFaces(VecDH& faceBox, - VecDH& faceMorton) { - VecDH faceNew2Old(NumTri()); - auto policy = autoPolicy(faceNew2Old.size()); - sequence(policy, faceNew2Old.begin(), faceNew2Old.end()); - - sort_by_key(policy, faceMorton.begin(), faceMorton.end(), - zip(faceBox.begin(), faceNew2Old.begin())); - - // Tris were flagged for removal with pairedHalfedge = -1 and assigned kNoCode - // to sort them to the end, which allows them to be removed. - const int newNumTri = - find(policy, faceMorton.begin(), - faceMorton.end(), kNoCode) - - faceMorton.begin(); - faceBox.resize(newNumTri); - faceMorton.resize(newNumTri); - faceNew2Old.resize(newNumTri); - - GatherFaces(faceNew2Old); -} - -/** - * Creates the halfedge_ vector for this manifold by copying a set of faces from - * another manifold, given by oldHalfedge. Input faceNew2Old defines the old - * faces to gather into this. - */ -void Manifold::Impl::GatherFaces(const VecDH& faceNew2Old) { - const int numTri = faceNew2Old.size(); - if (meshRelation_.triBary.size() == NumTri()) - Permute(meshRelation_.triBary, faceNew2Old); - - if (faceNormal_.size() == NumTri()) Permute(faceNormal_, faceNew2Old); - - VecDH oldHalfedge(std::move(halfedge_)); - VecDH oldHalfedgeTangent(std::move(halfedgeTangent_)); - VecDH faceOld2New(oldHalfedge.size() / 3); - auto policy = autoPolicy(numTri); - scatter(policy, countAt(0), countAt(numTri), faceNew2Old.begin(), - faceOld2New.begin()); - - halfedge_.resize(3 * numTri); - if (oldHalfedgeTangent.size() != 0) halfedgeTangent_.resize(3 * numTri); - for_each_n(policy, countAt(0), numTri, - ReindexFace({halfedge_.ptrD(), halfedgeTangent_.ptrD(), - oldHalfedge.cptrD(), oldHalfedgeTangent.cptrD(), - faceNew2Old.cptrD(), faceOld2New.cptrD()})); -} - -void Manifold::Impl::GatherFaces(const Impl& old, - const VecDH& faceNew2Old) { - const int numTri = faceNew2Old.size(); - meshRelation_.triBary.resize(numTri); - auto policy = autoPolicy(numTri); - gather(policy, faceNew2Old.begin(), faceNew2Old.end(), - old.meshRelation_.triBary.begin(), meshRelation_.triBary.begin()); - meshRelation_.barycentric = old.meshRelation_.barycentric; - - if (old.faceNormal_.size() == old.NumTri()) { - faceNormal_.resize(numTri); - gather(policy, faceNew2Old.begin(), faceNew2Old.end(), - old.faceNormal_.begin(), faceNormal_.begin()); - } - - VecDH faceOld2New(old.NumTri()); - scatter(policy, countAt(0), countAt(numTri), faceNew2Old.begin(), - faceOld2New.begin()); - - halfedge_.resize(3 * numTri); - if (old.halfedgeTangent_.size() != 0) halfedgeTangent_.resize(3 * numTri); - for_each_n(policy, countAt(0), numTri, - ReindexFace({halfedge_.ptrD(), halfedgeTangent_.ptrD(), - old.halfedge_.cptrD(), old.halfedgeTangent_.cptrD(), - faceNew2Old.cptrD(), faceOld2New.cptrD()})); -} -} // namespace manifold diff --git a/IfcPlusPlus/src/external/manifold/src/polygon/CMakeLists.txt b/IfcPlusPlus/src/external/manifold/src/polygon/CMakeLists.txt deleted file mode 100644 index c061c4052..000000000 --- a/IfcPlusPlus/src/external/manifold/src/polygon/CMakeLists.txt +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright 2020 The Manifold Authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -project (polygon) - -file(GLOB_RECURSE SOURCE_FILES CONFIGURE_DEPENDS *.cpp) -add_library(${PROJECT_NAME} ${SOURCE_FILES}) - -target_include_directories(${PROJECT_NAME} - PUBLIC ${PROJECT_SOURCE_DIR}/include -) -target_link_libraries( ${PROJECT_NAME} - PUBLIC utilities -) - -target_compile_options(${PROJECT_NAME} PRIVATE ${MANIFOLD_FLAGS}) -target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_14) diff --git a/IfcPlusPlus/src/external/manifold/src/polygon/include/polygon.h b/IfcPlusPlus/src/external/manifold/src/polygon/include/polygon.h deleted file mode 100644 index 5438efb6d..000000000 --- a/IfcPlusPlus/src/external/manifold/src/polygon/include/polygon.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2021 The Manifold Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once -#include - -#include "public.h" - -namespace manifold { - -/** @addtogroup Private - * @{ - */ -std::vector Triangulate(const Polygons &polys, - float precision = -1); - -ExecutionParams &PolygonParams(); -/** @} */ -} // namespace manifold \ No newline at end of file diff --git a/IfcPlusPlus/src/external/manifold/src/polygon/src/polygon.cpp b/IfcPlusPlus/src/external/manifold/src/polygon/src/polygon.cpp deleted file mode 100644 index 81d9ce730..000000000 --- a/IfcPlusPlus/src/external/manifold/src/polygon/src/polygon.cpp +++ /dev/null @@ -1,1077 +0,0 @@ -// Copyright 2021 The Manifold Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "polygon.h" - -#include -#include -#include -#include -#include -#include - -#include "optional_assert.h" - -namespace { -using namespace manifold; - -ExecutionParams params; - -#ifdef MANIFOLD_DEBUG -struct Polyedge { - int startVert, endVert; -}; - -bool OverlapAssert(bool condition, const char *file, int line, - const std::string &cond, const std::string &msg) { - if (!params.processOverlaps && !condition) { - std::ostringstream output; - output << "Error in file: " << file << " (" << line << "): \'" << cond - << "\' is false: " << msg; - throw geometryErr(output.str()); - } - return condition; -} - -/** - * Only use directly inside of the SweepForward() and SweepBack() functions! If - * the asserted condition is false, it implies the monotone subdivision has - * failed. This is most likely due to the input polygons being overlapped by - * more than the input precision, but if not, then it indicates a bug. Either - * way subdivision processing stops: if params.processOverlaps is false, then an - * exception is thrown. Otherwise this returns true from the sweep function, - * causing polygons to be left in their original state. - * - * The input polygons are then triangulated by the monotone triangulator, which - * is robust enough to create a manifold triangulation for all input, but it - * will not be geometrically-valid in this case. It may create inverted - * triangles which are significantly larger than precision, but it depends on - * the nature of the overlap. - */ -#define OVERLAP_ASSERT(condition, msg) \ - if (!OverlapAssert(condition, __FILE__, __LINE__, #condition, msg)) \ - return true; - -#define PRINT(msg) \ - if (params.verbose) std::cout << msg << std::endl; - -std::vector Polygons2Edges(const Polygons &polys) { - std::vector halfedges; - for (const auto &poly : polys) { - for (int i = 1; i < poly.size(); ++i) { - halfedges.push_back({poly[i - 1].idx, poly[i].idx}); - } - halfedges.push_back({poly.back().idx, poly[0].idx}); - } - return halfedges; -} - -std::vector Triangles2Edges( - const std::vector &triangles) { - std::vector halfedges; - for (const glm::ivec3 &tri : triangles) { - halfedges.push_back({tri[0], tri[1]}); - halfedges.push_back({tri[1], tri[2]}); - halfedges.push_back({tri[2], tri[0]}); - } - return halfedges; -} - -void CheckTopology(const std::vector &halfedges) { - ASSERT(halfedges.size() % 2 == 0, topologyErr, "Odd number of halfedges."); - size_t n_edges = halfedges.size() / 2; - std::vector forward(halfedges.size()), backward(halfedges.size()); - - auto end = std::copy_if(halfedges.begin(), halfedges.end(), forward.begin(), - [](Polyedge e) { return e.endVert > e.startVert; }); - ASSERT(std::distance(forward.begin(), end) == n_edges, topologyErr, - "Half of halfedges should be forward."); - forward.resize(n_edges); - - end = std::copy_if(halfedges.begin(), halfedges.end(), backward.begin(), - [](Polyedge e) { return e.endVert < e.startVert; }); - ASSERT(std::distance(backward.begin(), end) == n_edges, topologyErr, - "Half of halfedges should be backward."); - backward.resize(n_edges); - - std::for_each(backward.begin(), backward.end(), - [](Polyedge &e) { std::swap(e.startVert, e.endVert); }); - auto cmp = [](const Polyedge &a, const Polyedge &b) { - return a.startVert < b.startVert || - (a.startVert == b.startVert && a.endVert < b.endVert); - }; - std::sort(forward.begin(), forward.end(), cmp); - std::sort(backward.begin(), backward.end(), cmp); - for (int i = 0; i < n_edges; ++i) { - ASSERT(forward[i].startVert == backward[i].startVert && - forward[i].endVert == backward[i].endVert, - topologyErr, "Forward and backward edge do not match."); - if (i > 0) { - ASSERT(forward[i - 1].startVert != forward[i].startVert || - forward[i - 1].endVert != forward[i].endVert, - topologyErr, "Not a 2-manifold."); - ASSERT(backward[i - 1].startVert != backward[i].startVert || - backward[i - 1].endVert != backward[i].endVert, - topologyErr, "Not a 2-manifold."); - } - } -} - -void CheckTopology(const std::vector &triangles, - const Polygons &polys) { - std::vector halfedges = Triangles2Edges(triangles); - std::vector openEdges = Polygons2Edges(polys); - for (Polyedge e : openEdges) { - halfedges.push_back({e.endVert, e.startVert}); - } - CheckTopology(halfedges); -} - -void CheckGeometry(const std::vector &triangles, - const Polygons &polys, float precision) { - std::map vertPos; - for (const auto &poly : polys) { - for (int i = 0; i < poly.size(); ++i) { - vertPos[poly[i].idx] = poly[i].pos; - } - } - ASSERT(std::all_of(triangles.begin(), triangles.end(), - [&vertPos, precision](const glm::ivec3 &tri) { - return CCW(vertPos[tri[0]], vertPos[tri[1]], - vertPos[tri[2]], precision) >= 0; - }), - geometryErr, "triangulation is not entirely CCW!"); -} - -void Dump(const Polygons &polys) { - for (auto poly : polys) { - std::cout << "polys.push_back({" << std::setprecision(9) << std::endl; - for (auto v : poly) { - std::cout << " {glm::vec2(" << v.pos.x << ", " << v.pos.y << "), " - << v.idx << "}, //" << std::endl; - } - std::cout << "});" << std::endl; - } - for (auto poly : polys) { - std::cout << "array([" << std::endl; - for (auto v : poly) { - std::cout << " [" << v.pos.x << ", " << v.pos.y << "]," << std::endl; - } - std::cout << "])" << std::endl; - } -} - -void PrintFailure(const std::exception &e, const Polygons &polys, - std::vector &triangles, float precision) { - std::cout << "-----------------------------------" << std::endl; - std::cout << "Triangulation failed! Precision = " << precision << std::endl; - std::cout << e.what() << std::endl; - Dump(polys); - std::cout << "produced this triangulation:" << std::endl; - for (int j = 0; j < triangles.size(); ++j) { - std::cout << triangles[j][0] << ", " << triangles[j][1] << ", " - << triangles[j][2] << std::endl; - } -} -#else -#define OVERLAP_ASSERT(condition, msg) \ - if (!(condition)) return true; -#define PRINT(msg) -#endif - -/** - * The class first turns input polygons into monotone polygons, then - * triangulates them using the above class. - */ -class Monotones { - public: - Monotones(const Polygons &polys, float precision) : precision_(precision) { - VertItr start, last, current; - float bound = 0; - for (const SimplePolygon &poly : polys) { - for (int i = 0; i < poly.size(); ++i) { - monotones_.push_back({poly[i].pos, // - poly[i].idx, // - 0, monotones_.end(), monotones_.end(), - activePairs_.end(), activePairs_.end()}); - bound = glm::max( - bound, glm::max(glm::abs(poly[i].pos.x), glm::abs(poly[i].pos.y))); - - current = std::prev(monotones_.end()); - if (i == 0) - start = current; - else - Link(last, current); - last = current; - } - Link(current, start); - } - - if (precision_ < 0) precision_ = bound * kTolerance; - - if (SweepForward()) return; - Check(); - - if (SweepBack()) return; - Check(); - } - - void Triangulate(std::vector &triangles) { - // Save the sweep-line order in the vert to check further down. - int i = 1; - for (auto &vert : monotones_) { - vert.index = i++; - } - int triangles_left = monotones_.size(); - VertItr start = monotones_.begin(); - while (start != monotones_.end()) { - PRINT(start->mesh_idx); - Triangulator triangulator(start, precision_); - start->SetProcessed(true); - VertItr vR = start->right; - VertItr vL = start->left; - while (vR != vL) { - // Process the neighbor vert that is next in the sweep-line. - if (vR->index < vL->index) { - PRINT(vR->mesh_idx); - triangulator.ProcessVert(vR, true, false, triangles); - vR->SetProcessed(true); - vR = vR->right; - } else { - PRINT(vL->mesh_idx); - triangulator.ProcessVert(vL, false, false, triangles); - vL->SetProcessed(true); - vL = vL->left; - } - } - PRINT(vR->mesh_idx); - triangulator.ProcessVert(vR, true, true, triangles); - vR->SetProcessed(true); - // validation - ASSERT(triangulator.NumTriangles() > 0, topologyErr, - "Monotone produced no triangles."); - triangles_left -= 2 + triangulator.NumTriangles(); - // Find next monotone - start = std::find_if(monotones_.begin(), monotones_.end(), - [](const VertAdj &v) { return !v.Processed(); }); - } - ASSERT(triangles_left == 0, topologyErr, - "Triangulation produced wrong number of triangles."); - } - - // A variety of sanity checks on the data structure. Expensive checks are only - // performed if params.intermediateChecks = true. - void Check() { -#ifdef MANIFOLD_DEBUG - if (!params.intermediateChecks) return; - std::vector edges; - for (VertItr vert = monotones_.begin(); vert != monotones_.end(); vert++) { - vert->SetProcessed(false); - edges.push_back({vert->mesh_idx, vert->right->mesh_idx}); - ASSERT(vert->right->right != vert, topologyErr, "two-edge monotone!"); - ASSERT(vert->left->right == vert, topologyErr, - "monotone vert neighbors don't agree!"); - } - if (params.verbose) { - VertItr start = monotones_.begin(); - while (start != monotones_.end()) { - start->SetProcessed(true); - PRINT("monotone start: " << start->mesh_idx << ", " << start->pos.y); - VertItr v = start->right; - while (v != start) { - PRINT(v->mesh_idx << ", " << v->pos.y); - v->SetProcessed(true); - v = v->right; - } - PRINT(""); - start = std::find_if(monotones_.begin(), monotones_.end(), - [](const VertAdj &v) { return !v.Processed(); }); - } - } -#endif - } - - float GetPrecision() const { return precision_; } - - private: - struct VertAdj; - typedef std::list::iterator VertItr; - struct EdgePair; - typedef std::list::iterator PairItr; - enum VertType { START, WESTSIDE, EASTSIDE, MERGE, END, SKIP }; - - std::list monotones_; // sweep-line list of verts - std::list activePairs_; // west to east list of monotone edge pairs - std::list inactivePairs_; // completed monotones - float precision_; // a triangle of this height or less is degenerate - - /** - * This is the data structure of the polygons themselves. They are stored as a - * list in sweep-line order. The left and right pointers form the polygons, - * while the mesh_idx describes the input indices that will be transferred to - * the output triangulation. The edgeRight value represents an extra contraint - * from the mesh Boolean algorithm. - */ - struct VertAdj { - glm::vec2 pos; - int mesh_idx; // This is a global index into the manifold. - int index; - VertItr left, right; - PairItr eastPair, westPair; - - bool Processed() const { return index < 0; } - void SetSkip() { index = -2; } - void SetProcessed(bool processed) { - if (index == -2) return; - index = processed ? -1 : 0; - } - bool IsStart() const { - return (left->pos.y >= pos.y && right->pos.y > pos.y) || - (left->pos.y == pos.y && right->pos.y == pos.y && - left->pos.x <= pos.x && right->pos.x < pos.x); - } - bool IsPast(const VertItr other, float precision) const { - return pos.y > other->pos.y + precision; - } - bool operator<(const VertAdj &other) const { return pos.y < other.pos.y; } - }; - - /** - * The EdgePairs form the two active edges of a monotone polygon as they are - * being constructed. The sweep-line is horizontal and moves from -y to +y, or - * South to North. The West edge is a backwards edge while the East edge is - * forwards, a topological constraint. If the polygon is geometrically valid, - * then the West edge will also be to the -x side of the East edge, hence the - * name. - * - * The purpose of the certainty booleans is to represent if we're sure the - * pairs (or monotones) are in the right order. This is uncertain if they are - * degenerate, for instance if several active edges are colinear (within - * tolerance). If the order is uncertain, then as each vert is processed, if - * it yields new information, it can cause the order to be updated until - * certain. - */ - - struct EdgePair { - VertItr vWest, vEast, vMerge; - PairItr nextPair; - bool westCertain, eastCertain, startCertain; - - int WestOf(VertItr vert, float precision) const { - int westOf = CCW(vEast->right->pos, vEast->pos, vert->pos, precision); - if (westOf == 0 && !vert->right->Processed()) - westOf = - CCW(vEast->right->pos, vEast->pos, vert->right->pos, precision); - if (westOf == 0 && !vert->left->Processed()) - westOf = CCW(vEast->right->pos, vEast->pos, vert->left->pos, precision); - return westOf; - } - - int EastOf(VertItr vert, float precision) const { - int eastOf = CCW(vWest->pos, vWest->left->pos, vert->pos, precision); - if (eastOf == 0 && !vert->right->Processed()) - eastOf = CCW(vWest->pos, vWest->left->pos, vert->right->pos, precision); - if (eastOf == 0 && !vert->left->Processed()) - eastOf = CCW(vWest->pos, vWest->left->pos, vert->left->pos, precision); - return eastOf; - } - }; - - /** - * This class takes sequential verts of a monotone polygon and outputs a - * geometrically valid triangulation, step by step. - */ - class Triangulator { - public: - Triangulator(VertItr vert, float precision) : precision_(precision) { - reflex_chain_.push(vert); - other_side_ = vert; - } - int NumTriangles() const { return triangles_output_; } - - /** - * The vert, vi, must attach to the free end (specified by onRight) of the - * polygon that has been input so far. The verts must also be processed in - * sweep-line order to get a geometrically valid result. If not, then the - * polygon is not monotone, as the result should be topologically valid, but - * not geometrically. The parameter, last, must be set true only for the - * final point, as this ensures the last triangle is output. - */ - void ProcessVert(const VertItr vi, bool onRight, bool last, - std::vector &triangles) { - VertItr v_top = reflex_chain_.top(); - if (reflex_chain_.size() < 2) { - reflex_chain_.push(vi); - onRight_ = onRight; - return; - } - reflex_chain_.pop(); - VertItr vj = reflex_chain_.top(); - if (onRight_ == onRight && !last) { - // This only creates enough triangles to ensure the reflex chain is - // still reflex. - PRINT("same chain"); - int ccw = CCW(vi->pos, vj->pos, v_top->pos, precision_); - while (ccw == (onRight_ ? 1 : -1) || ccw == 0) { - AddTriangle(triangles, vi, vj, v_top); - v_top = vj; - reflex_chain_.pop(); - if (reflex_chain_.empty()) break; - vj = reflex_chain_.top(); - ccw = CCW(vi->pos, vj->pos, v_top->pos, precision_); - } - reflex_chain_.push(v_top); - reflex_chain_.push(vi); - } else { - // This branch empties the reflex chain and switches sides. It must be - // used for the last point, as it will output all the triangles - // regardless of geometry. - PRINT("different chain"); - onRight_ = !onRight_; - VertItr v_last = v_top; - while (!reflex_chain_.empty()) { - vj = reflex_chain_.top(); - AddTriangle(triangles, vi, v_last, vj); - v_last = vj; - reflex_chain_.pop(); - } - reflex_chain_.push(v_top); - reflex_chain_.push(vi); - other_side_ = v_top; - } - } - - private: - std::stack reflex_chain_; - VertItr other_side_; // The end vertex across from the reflex chain - bool onRight_; // The side the reflex chain is on - int triangles_output_ = 0; - const float precision_; - - void AddTriangle(std::vector &triangles, VertItr v0, VertItr v1, - VertItr v2) { - if (!onRight_) std::swap(v1, v2); - triangles.emplace_back(v0->mesh_idx, v1->mesh_idx, v2->mesh_idx); - ++triangles_output_; - PRINT(triangles.back()); - } - }; - - void Link(VertItr left, VertItr right) { - left->right = right; - right->left = left; - } - - void SetVWest(PairItr pair, VertItr vert) { - pair->vWest = vert; - vert->eastPair = pair; - } - - void SetVEast(PairItr pair, VertItr vert) { - pair->vEast = vert; - vert->westPair = pair; - } - - void SetEastCertainty(PairItr westPair, bool certain) { - westPair->eastCertain = certain; - std::next(westPair)->westCertain = certain; - } - - PairItr GetPair(VertItr vert, VertType type) const { - // MERGE returns westPair, as this is the one that will be removed. - return type == WESTSIDE ? vert->eastPair : vert->westPair; - } - - bool Coincident(glm::vec2 p0, glm::vec2 p1) const { - glm::vec2 sep = p0 - p1; - return glm::dot(sep, sep) < precision_ * precision_; - } - - void CloseEnd(VertItr vert) { - PairItr eastPair = vert->right->eastPair; - PairItr westPair = vert->left->westPair; - SetVWest(eastPair, vert); - SetVEast(westPair, vert); - westPair->westCertain = true; - westPair->eastCertain = true; - } - - /** - * This function is shared between the forward and backward sweeps and - * determines the topology of the vertex relative to the sweep line. - */ - VertType ProcessVert(VertItr vert) { - PairItr eastPair = vert->right->eastPair; - PairItr westPair = vert->left->westPair; - if (vert->right->Processed()) { - if (vert->left->Processed()) { - if (westPair == eastPair) { - // facing in - PRINT("END"); - CloseEnd(vert); - return END; - } else if (westPair != activePairs_.end() && - std::next(westPair) == eastPair) { - // facing out - PRINT("MERGE"); - CloseEnd(vert); - // westPair will be removed and eastPair takes over. - SetVWest(eastPair, westPair->vWest); - return MERGE; - } else { // not neighbors - PRINT("SKIP"); - return SKIP; - } - } else { - if (!eastPair->vEast->right->IsPast(vert, precision_) && - vert->IsPast(eastPair->vEast, precision_) && - vert->pos.x > eastPair->vEast->right->pos.x + precision_) { - PRINT("SKIP WEST"); - return SKIP; - } - SetVWest(eastPair, vert); - PRINT("WESTSIDE"); - return WESTSIDE; - } - } else { - if (vert->left->Processed()) { - if (!westPair->vWest->left->IsPast(vert, precision_) && - vert->IsPast(westPair->vWest, precision_) && - vert->pos.x < westPair->vWest->left->pos.x - precision_) { - PRINT("SKIP EAST"); - return SKIP; - } - SetVEast(westPair, vert); - PRINT("EASTSIDE"); - return EASTSIDE; - } else { - PRINT("START"); - return START; - } - } - } - - /** - * Remove this pair, but save it and mark the pair it was next to. When the - * reverse sweep happens, it will be placed next to its last neighbor instead - * of using geometry. - */ - void RemovePair(PairItr pair) { - pair->nextPair = std::next(pair); - inactivePairs_.splice(inactivePairs_.end(), activePairs_, pair); - } - - /** - * When vert is a START, this determines if it is backwards (forming a void or - * hole). Usually the first return is adequate, but if it is degenerate, the - * function will continue to search up the neighbors until the degeneracy is - * broken and a certain answer is returned. Like CCW, this function returns 1 - * for a hole, -1 for a start, and 0 only if the entire polygon degenerates to - * a polyline. - */ - int IsHole(VertItr vert) const { - VertItr left = vert->left; - VertItr right = vert->right; - VertItr center = vert; - // TODO: if left or right is Processed(), determine from east/west - while (left != right) { - if (Coincident(left->pos, center->pos)) { - left = left->left; - continue; - } - if (Coincident(right->pos, center->pos)) { - right = right->right; - continue; - } - if (Coincident(left->pos, right->pos)) { - vert = center; - center = left; - left = left->left; - if (left == right) break; - right = right->right; - continue; - } - int isHole = CCW(right->pos, center->pos, left->pos, precision_); - if (center != vert) { - isHole += CCW(left->pos, center->pos, vert->pos, precision_) + - CCW(vert->pos, center->pos, right->pos, precision_); - } - if (isHole != 0) return isHole; - - glm::vec2 edgeLeft = left->pos - center->pos; - glm::vec2 edgeRight = right->pos - center->pos; - if (glm::dot(edgeLeft, edgeRight) > 0) { - if (glm::dot(edgeLeft, edgeLeft) < glm::dot(edgeRight, edgeRight)) { - center = left; - left = left->left; - } else { - center = right; - right = right->right; - } - } else { - if (left->pos.y < right->pos.y) { - left = left->left; - } else { - right = right->right; - } - } - } - return 0; - } - - /** - * If the simple polygon connected to the input vert degenerates to a single - * line (more strict than IsHole==0), then any triangulation is admissible, - * since every possible triangle will be degenerate. - */ - bool IsColinearPoly(const VertItr start) const { - VertItr vert = start; - VertItr left = start; - VertItr right = left->right; - // Find the longest edge to improve error - float length2 = 0; - while (right != start) { - glm::vec2 edge = left->pos - right->pos; - const float l2 = glm::dot(edge, edge); - if (l2 > length2) { - length2 = l2; - vert = left; - } - left = right; - right = right->right; - } - - right = vert->right; - left = vert->left; - while (left != vert) { - if (CCW(left->pos, vert->pos, right->pos, precision_) != 0) return false; - left = left->left; - } - return true; - } - - /** - * Causes the verts of the simple polygon attached to the input vert to be - * skipped during the forward and backward sweeps, causing this polygon to be - * triangulated as though it is monotone. - */ - void SkipPoly(VertItr vert) { - vert->SetSkip(); - VertItr right = vert->right; - while (right != vert) { - right->SetSkip(); - right = right->right; - } - } - - /** - * A backwards pair (hole) must be interior to a forwards pair for geometric - * validity. In this situation, this function is used to swap their east edges - * such that they become forward neighbor pairs. The outside becomes westPair - * and inside becomes eastPair. - */ - void SwapHole(PairItr outside, PairItr inside) { - VertItr tmp = outside->vEast; - SetVEast(outside, inside->vEast); - SetVEast(inside, tmp); - inside->eastCertain = outside->eastCertain; - - activePairs_.splice(std::next(outside), activePairs_, inside); - SetEastCertainty(outside, true); - } - - /** - * This is the key function for handling east-west degeneracies, and is the - * purpose of running the sweep-line forwards and backwards. If the ordering - * of inputPair is uncertain, this function uses the edge ahead of vert to - * check if this new bit of geometric information is enough to place the pair - * with certainty. It can also invert the pair if it is determined to be a - * hole, in which case the inputPair becomes the eastPair while the pair it is - * inside of becomes the westPair. - * - * This function normally returns false, but will instead return true if the - * certainties conflict, indicating this vertex is not yet geometrically valid - * and must be skipped. - */ - bool ShiftEast(const VertItr vert, const PairItr inputPair, - const bool isHole) { - if (inputPair->eastCertain) return false; - - PairItr potentialPair = std::next(inputPair); - while (potentialPair != activePairs_.end()) { - const int EastOf = potentialPair->EastOf(vert, precision_); - // This does not trigger a skip because ShiftWest may still succeed, and - // if not it will mark the skip. - if (EastOf > 0 && isHole) return false; - - if (EastOf >= 0 && !isHole) { // in the right place - activePairs_.splice(potentialPair, activePairs_, inputPair); - SetEastCertainty(inputPair, EastOf != 0); - return false; - } - - const int outside = potentialPair->WestOf(vert, precision_); - if (outside <= 0 && isHole) { // certainly a hole - SwapHole(potentialPair, inputPair); - return false; - } - ++potentialPair; - } - if (isHole) return true; - - activePairs_.splice(activePairs_.end(), activePairs_, inputPair); - inputPair->eastCertain = true; - return false; - } - - /** - * Identical to the above function, but swapped to search westward instead. - */ - bool ShiftWest(const VertItr vert, const PairItr inputPair, - const bool isHole) { - if (inputPair->westCertain) return false; - - PairItr potentialPair = inputPair; - while (potentialPair != activePairs_.begin()) { - --potentialPair; - const int WestOf = potentialPair->WestOf(vert, precision_); - if (WestOf > 0 && isHole) return true; - - if (WestOf >= 0 && !isHole) { // in the right place - SetEastCertainty(potentialPair, WestOf != 0); - if (++potentialPair != inputPair) - activePairs_.splice(potentialPair, activePairs_, inputPair); - return false; - } - - const int outside = potentialPair->EastOf(vert, precision_); - if (outside <= 0 && isHole) { // certainly a hole - SwapHole(potentialPair, inputPair); - return false; - } - } - if (isHole) return true; - - if (inputPair != activePairs_.begin()) - activePairs_.splice(activePairs_.begin(), activePairs_, inputPair); - inputPair->westCertain = true; - return false; - } - - /** - * This function sweeps forward (South to North) keeping track of the - * monotones and reordering degenerates (monotone ordering in the x-direction - * and sweep line ordering in the y-direction). The input polygons - * (monotones_) is not changed during this process. - */ - bool SweepForward() { - // Reversed so that minimum element is at queue.top() / vector.back(). - auto cmp = [](VertItr a, VertItr b) { return *b < *a; }; - std::priority_queue, decltype(cmp)> - nextAttached(cmp); - - std::vector starts; - for (VertItr v = monotones_.begin(); v != monotones_.end(); v++) { - if (v->IsStart()) { - starts.push_back(v); - } - } - std::sort(starts.begin(), starts.end(), cmp); - - std::vector skipped; - VertItr insertAt = monotones_.begin(); - - while (insertAt != monotones_.end()) { - // fallback for completely degenerate polygons that have no starts. - VertItr vert = insertAt; - if (!nextAttached.empty() && - (starts.empty() || - !nextAttached.top()->IsPast(starts.back(), precision_))) { - // Prefer neighbors, which may process starts without needing a new - // pair. - vert = nextAttached.top(); - nextAttached.pop(); - } else if (!starts.empty()) { - // Create a new pair with the next vert from the sorted list of starts. - vert = starts.back(); - starts.pop_back(); - } else { - ++insertAt; - } - - PRINT("mesh_idx = " << vert->mesh_idx); - - if (vert->Processed()) continue; - - OVERLAP_ASSERT( - skipped.empty() || !vert->IsPast(skipped.back(), precision_), - "Not Geometrically Valid! None of the skipped verts is valid."); - - VertType type = ProcessVert(vert); - - PairItr newPair = activePairs_.end(); - bool isHole = false; - if (type == START) { - newPair = activePairs_.insert( - activePairs_.begin(), {vert, vert, monotones_.end(), - activePairs_.end(), false, false, false}); - SetVWest(newPair, vert); - SetVEast(newPair, vert); - const int hole = IsHole(vert); - if (hole == 0 && IsColinearPoly(vert)) { - PRINT("Skip colinear polygon"); - SkipPoly(vert); - activePairs_.erase(newPair); - continue; - } - isHole = hole > 0; - } - - const PairItr pair = GetPair(vert, type); - OVERLAP_ASSERT(type == SKIP || pair != activePairs_.end(), - "No active pair!"); - - if (type != SKIP && ShiftEast(vert, pair, isHole)) type = SKIP; - if (type != SKIP && ShiftWest(vert, pair, isHole)) type = SKIP; - - if (type == SKIP) { - OVERLAP_ASSERT(std::next(insertAt) != monotones_.end(), - "Not Geometrically Valid! Tried to skip final vert."); - OVERLAP_ASSERT( - !nextAttached.empty() || !starts.empty(), - "Not Geometrically Valid! Tried to skip last queued vert."); - skipped.push_back(vert); - PRINT("Skipping vert"); - // If a new pair was added, remove it. - if (newPair != activePairs_.end()) { - activePairs_.erase(newPair); - vert->westPair = activePairs_.end(); - vert->eastPair = activePairs_.end(); - } - continue; - } - - if (vert == insertAt) - ++insertAt; - else - monotones_.splice(insertAt, monotones_, vert); - - switch (type) { - case WESTSIDE: - nextAttached.push(vert->left); - break; - case EASTSIDE: - nextAttached.push(vert->right); - break; - case START: - nextAttached.push(vert->left); - nextAttached.push(vert->right); - break; - case MERGE: - // Mark merge as hole for sweep-back. - pair->vMerge = vert; - case END: - RemovePair(pair); - break; - case SKIP: - break; - } - - vert->SetProcessed(true); - // Push skipped verts back into unprocessed queue. - while (!skipped.empty()) { - starts.push_back(skipped.back()); - skipped.pop_back(); - } - -#ifdef MANIFOLD_DEBUG - if (params.verbose) ListPairs(); -#endif - } - return false; - } // namespace - - /** - * This is the only function that actually changes monotones_; all the rest is - * bookkeeping. This divides polygons by connecting two verts. It duplicates - * these verts to break the polygons, then attaches them across to each other - * with two new edges. - */ - VertItr SplitVerts(VertItr north, VertItr south) { - // at split events, add duplicate vertices to end of list and reconnect - PRINT("split from " << north->mesh_idx << " to " << south->mesh_idx); - - VertItr northEast = monotones_.insert(north, *north); - Link(north->left, northEast); - northEast->SetProcessed(true); - - VertItr southEast = monotones_.insert(std::next(south), *south); - Link(southEast, south->right); - southEast->SetProcessed(true); - - Link(south, north); - Link(northEast, southEast); - - return northEast; - } - - /** - * This function sweeps back, splitting the input polygons - * into monotone polygons without doing a single geometric calculation. - * Instead everything is based on the topology saved from the forward sweep, - * primarily the relative ordering of new monotones. Even though the sweep is - * going back, the polygon is considered rotated, so we still refer to - * sweeping from South to North and the pairs as ordered from West to East - * (though this is now the opposite order from the forward sweep). - */ - bool SweepBack() { - for (auto &vert : monotones_) vert.SetProcessed(false); - - VertItr vert = monotones_.end(); - while (vert != monotones_.begin()) { - --vert; - - PRINT("mesh_idx = " << vert->mesh_idx); - - if (vert->Processed()) continue; - - VertType type = ProcessVert(vert); - OVERLAP_ASSERT(type != SKIP, "SKIP should not happen on reverse sweep!"); - - PairItr westPair = GetPair(vert, type); - //OVERLAP_ASSERT(westPair != activePairs_.end(), "No active pair!"); - - switch (type) { - case MERGE: { - PairItr eastPair = std::next(westPair); - if (eastPair->vMerge != monotones_.end()) - vert = SplitVerts(vert, eastPair->vMerge); - eastPair->vMerge = vert; - } - case END: - RemovePair(westPair); - case WESTSIDE: - case EASTSIDE: - if (westPair->vMerge != monotones_.end()) { - VertItr eastVert = SplitVerts(vert, westPair->vMerge); - if (type == WESTSIDE) westPair->vWest = eastVert; - westPair->vMerge = monotones_.end(); - } - break; - case START: { - // Due to sweeping in the opposite direction, east and west are - // swapped and what was the next pair is now the previous pair and - // begin and end are swapped. - PairItr eastPair = westPair; - westPair = eastPair->nextPair; - activePairs_.splice(westPair == activePairs_.end() - ? activePairs_.begin() - : std::next(westPair), - inactivePairs_, eastPair); - - if (eastPair->vMerge == vert) { // Hole - VertItr split = westPair->vMerge != monotones_.end() - ? westPair->vMerge - : westPair->vWest->pos.y < westPair->vEast->pos.y - ? westPair->vWest - : westPair->vEast; - VertItr eastVert = SplitVerts(vert, split); - westPair->vMerge = monotones_.end(); - eastPair->vMerge = monotones_.end(); - SetVWest(eastPair, eastVert); - SetVEast(eastPair, split == westPair->vEast ? eastVert->right - : westPair->vEast); - SetVEast(westPair, vert); - } else { // Start - SetVWest(eastPair, vert); - SetVEast(eastPair, vert); - } - break; - } - case SKIP: - break; - } - - vert->SetProcessed(true); - -#ifdef MANIFOLD_DEBUG - if (params.verbose) ListPairs(); -#endif - } - return false; - } - -#ifdef MANIFOLD_DEBUG - void ListPairs() const { - std::cout << "active edges:" << std::endl; - for (const EdgePair &pair : activePairs_) { - std::cout << (pair.westCertain ? "certain " : "uncertain "); - std::cout << "edge West: S = " << pair.vWest->mesh_idx - << ", N = " << pair.vWest->left->mesh_idx << std::endl; - if (&*(pair.vWest->eastPair) != &pair) - std::cout << "west does not point back!" << std::endl; - - std::cout << (pair.eastCertain ? "certain " : "uncertain "); - std::cout << "edge East: S = " << pair.vEast->mesh_idx - << ", N = " << pair.vEast->right->mesh_idx << std::endl; - if (&*(pair.vEast->westPair) != &pair) - std::cout << "east does not point back!" << std::endl; - } - } -#endif -}; -} // namespace - -namespace manifold { - -/** - * @brief Triangulates a set of /epsilon-valid polygons. - * - * @param polys The set of polygons, wound CCW and representing multiple - * polygons and/or holes. These have 2D-projected positions as well as - * references back to the original vertices - * @param precision The value of epsilon, bounding the uncertainty of the input - * @return std::vector The triangles, referencing the original - * vertex indicies. - */ -std::vector Triangulate(const Polygons &polys, float precision) { - std::vector triangles; - try { - Monotones monotones(polys, precision); - monotones.Triangulate(triangles); -#ifdef MANIFOLD_DEBUG - if (params.intermediateChecks) { - CheckTopology(triangles, polys); - if (!params.processOverlaps) { - CheckGeometry(triangles, polys, 2 * monotones.GetPrecision()); - } - } - } catch (const geometryErr &e) { - if (!params.suppressErrors) { - PrintFailure(e, polys, triangles, precision); - } - throw; - } catch (const std::exception &e) { - PrintFailure(e, polys, triangles, precision); - throw; -#else - } catch (const std::exception &e) { -#endif - } - return triangles; -} - -ExecutionParams &PolygonParams() { return params; } - -} // namespace manifold diff --git a/IfcPlusPlus/src/external/manifold/src/properties.cpp b/IfcPlusPlus/src/external/manifold/src/properties.cpp deleted file mode 100644 index 3560bdcb8..000000000 --- a/IfcPlusPlus/src/external/manifold/src/properties.cpp +++ /dev/null @@ -1,373 +0,0 @@ -// Copyright 2021 The Manifold Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include -#include - -#include - -#include "impl.h" -#include "par.h" - -namespace { -using namespace manifold; - -struct FaceAreaVolume { - const Halfedge* halfedges; - const glm::vec3* vertPos; - const float precision; - - __host__ __device__ thrust::pair operator()(int face) { - float perimeter = 0; - glm::vec3 edge[3]; - for (int i : {0, 1, 2}) { - const int j = (i + 1) % 3; - edge[i] = vertPos[halfedges[3 * face + j].startVert] - - vertPos[halfedges[3 * face + i].startVert]; - perimeter += glm::length(edge[i]); - } - glm::vec3 crossP = glm::cross(edge[0], edge[1]); - - float area = glm::length(crossP); - float volume = glm::dot(crossP, vertPos[halfedges[3 * face].startVert]); - - return area > perimeter * precision - ? thrust::make_pair(area / 2.0f, volume / 6.0f) - : thrust::make_pair(0.0f, 0.0f); - } -}; - -struct PosMin - : public thrust::binary_function { - __host__ __device__ glm::vec3 operator()(glm::vec3 a, glm::vec3 b) { - if (isnan(a.x)) return b; - if (isnan(b.x)) return a; - return glm::min(a, b); - } -}; - -struct PosMax - : public thrust::binary_function { - __host__ __device__ glm::vec3 operator()(glm::vec3 a, glm::vec3 b) { - if (isnan(a.x)) return b; - if (isnan(b.x)) return a; - return glm::max(a, b); - } -}; - -struct FiniteVert { - __host__ __device__ bool operator()(glm::vec3 v) { - return glm::all(glm::isfinite(v)); - } -}; - -struct MakeMinMax { - __host__ __device__ glm::ivec2 operator()(glm::ivec3 tri) { - return glm::ivec2(glm::min(tri[0], glm::min(tri[1], tri[2])), - glm::max(tri[0], glm::max(tri[1], tri[2]))); - } -}; - -struct MinMax - : public thrust::binary_function { - __host__ __device__ glm::ivec2 operator()(glm::ivec2 a, glm::ivec2 b) { - a[0] = glm::min(a[0], b[0]); - a[1] = glm::max(a[1], b[1]); - return a; - } -}; - -struct SumPair : public thrust::binary_function, - thrust::pair, - thrust::pair> { - __host__ __device__ thrust::pair operator()( - thrust::pair a, thrust::pair b) { - a.first += b.first; - a.second += b.second; - return a; - } -}; - -struct CurvatureAngles { - float* meanCurvature; - float* gaussianCurvature; - float* area; - float* degree; - const Halfedge* halfedge; - const glm::vec3* vertPos; - const glm::vec3* triNormal; - - __host__ __device__ void operator()(int tri) { - glm::vec3 edge[3]; - glm::vec3 edgeLength(0.0); - for (int i : {0, 1, 2}) { - const int startVert = halfedge[3 * tri + i].startVert; - const int endVert = halfedge[3 * tri + i].endVert; - edge[i] = vertPos[endVert] - vertPos[startVert]; - edgeLength[i] = glm::length(edge[i]); - edge[i] /= edgeLength[i]; - const int neighborTri = halfedge[3 * tri + i].pairedHalfedge / 3; - const float dihedral = - 0.25 * edgeLength[i] * - glm::asin(glm::dot(glm::cross(triNormal[tri], triNormal[neighborTri]), - edge[i])); - AtomicAdd(meanCurvature[startVert], dihedral); - AtomicAdd(meanCurvature[endVert], dihedral); - AtomicAdd(degree[startVert], 1.0f); - } - - glm::vec3 phi; - phi[0] = glm::acos(-glm::dot(edge[2], edge[0])); - phi[1] = glm::acos(-glm::dot(edge[0], edge[1])); - phi[2] = glm::pi() - phi[0] - phi[1]; - const float area3 = edgeLength[0] * edgeLength[1] * - glm::length(glm::cross(edge[0], edge[1])) / 6; - - for (int i : {0, 1, 2}) { - const int vert = halfedge[3 * tri + i].startVert; - AtomicAdd(gaussianCurvature[vert], -phi[i]); - AtomicAdd(area[vert], area3); - } - } -}; - -struct NormalizeCurvature { - __host__ __device__ void operator()( - thrust::tuple inOut) { - float& meanCurvature = thrust::get<0>(inOut); - float& gaussianCurvature = thrust::get<1>(inOut); - float area = thrust::get<2>(inOut); - float degree = thrust::get<3>(inOut); - float factor = degree / (6 * area); - meanCurvature *= factor; - gaussianCurvature *= factor; - } -}; - -struct CheckManifold { - const Halfedge* halfedges; - - __host__ __device__ bool operator()(int edge) { - const Halfedge halfedge = halfedges[edge]; - if (halfedge.startVert == -1 && halfedge.endVert == -1 && - halfedge.pairedHalfedge == -1) - return true; - - const Halfedge paired = halfedges[halfedge.pairedHalfedge]; - bool good = true; - good &= paired.pairedHalfedge == edge; - good &= halfedge.startVert != halfedge.endVert; - good &= halfedge.startVert == paired.endVert; - good &= halfedge.endVert == paired.startVert; - return good; - } -}; - -struct NoDuplicates { - const Halfedge* halfedges; - - __host__ __device__ bool operator()(int edge) { - const Halfedge halfedge = halfedges[edge]; - if (halfedge.startVert == -1 && halfedge.endVert == -1 && - halfedge.pairedHalfedge == -1) - return true; - return halfedge.startVert != halfedges[edge + 1].startVert || - halfedge.endVert != halfedges[edge + 1].endVert; - } -}; - -struct CheckCCW { - const Halfedge* halfedges; - const glm::vec3* vertPos; - const glm::vec3* triNormal; - const float tol; - - __host__ __device__ bool operator()(int face) { - if (halfedges[3 * face].pairedHalfedge < 0) return true; - - const glm::mat3x2 projection = GetAxisAlignedProjection(triNormal[face]); - glm::vec2 v[3]; - for (int i : {0, 1, 2}) - v[i] = projection * vertPos[halfedges[3 * face + i].startVert]; - - int ccw = CCW(v[0], v[1], v[2], glm::abs(tol)); - bool check = tol > 0 ? ccw >= 0 : ccw == 0; - -#ifdef MANIFOLD_DEBUG - if (tol > 0 && !check) { - glm::vec2 v1 = v[1] - v[0]; - glm::vec2 v2 = v[2] - v[0]; - float area = v1.x * v2.y - v1.y * v2.x; - float base2 = glm::max(glm::dot(v1, v1), glm::dot(v2, v2)); - float base = glm::sqrt(base2); - glm::vec3 V0 = vertPos[halfedges[3 * face].startVert]; - glm::vec3 V1 = vertPos[halfedges[3 * face + 1].startVert]; - glm::vec3 V2 = vertPos[halfedges[3 * face + 2].startVert]; - glm::vec3 norm = glm::cross(V1 - V0, V2 - V0); - printf( - "Tri %d does not match normal, approx height = %g, base = %g\n" - "tol = %g, area2 = %g, base2*tol2 = %g\n" - "normal = %g, %g, %g\n" - "norm = %g, %g, %g\nverts: %d, %d, %d\n", - face, area / base, base, tol, area * area, base2 * tol * tol, - triNormal[face].x, triNormal[face].y, triNormal[face].z, norm.x, - norm.y, norm.z, halfedges[3 * face].startVert, - halfedges[3 * face + 1].startVert, halfedges[3 * face + 2].startVert); - } -#endif - return check; - } -}; -} // namespace - -namespace manifold { - -/** - * Returns true if this manifold is in fact an oriented even manifold and all of - * the data structures are consistent. - */ -bool Manifold::Impl::IsManifold() const { - if (halfedge_.size() == 0) return true; - auto policy = autoPolicy(halfedge_.size()); - - return all_of(policy, countAt(0), countAt(halfedge_.size()), - CheckManifold({halfedge_.cptrD()})); -} - -/** - * Returns true if this manifold is in fact an oriented 2-manifold and all of - * the data structures are consistent. - */ -bool Manifold::Impl::Is2Manifold() const { - if (halfedge_.size() == 0) return true; - auto policy = autoPolicy(halfedge_.size()); - - if (!IsManifold()) return false; - - VecDH halfedge(halfedge_); - sort(policy, halfedge.begin(), halfedge.end()); - - return all_of(policy, countAt(0), countAt(2 * NumEdge() - 1), - NoDuplicates({halfedge.cptrD()})); -} - -/** - * Returns true if all triangles are CCW relative to their triNormals_. - */ -bool Manifold::Impl::MatchesTriNormals() const { - if (halfedge_.size() == 0 || faceNormal_.size() != NumTri()) return true; - return all_of(autoPolicy(NumTri()), countAt(0), countAt(NumTri()), - CheckCCW({halfedge_.cptrD(), vertPos_.cptrD(), - faceNormal_.cptrD(), 2 * precision_})); -} - -/** - * Returns the number of triangles that are colinear within precision_. - */ -int Manifold::Impl::NumDegenerateTris() const { - if (halfedge_.size() == 0 || faceNormal_.size() != NumTri()) return true; - return count_if(autoPolicy(NumTri()), countAt(0), countAt(NumTri()), - CheckCCW({halfedge_.cptrD(), vertPos_.cptrD(), - faceNormal_.cptrD(), -1 * precision_ / 2})); -} - -Properties Manifold::Impl::GetProperties() const { - if (IsEmpty()) return {0, 0}; - auto areaVolume = transform_reduce>( - autoPolicy(NumTri()), countAt(0), countAt(NumTri()), - FaceAreaVolume({halfedge_.cptrD(), vertPos_.cptrD(), precision_}), - thrust::make_pair(0.0f, 0.0f), SumPair()); - return {areaVolume.first, areaVolume.second}; -} - -Curvature Manifold::Impl::GetCurvature() const { - Curvature result; - if (IsEmpty()) return result; - VecDH vertMeanCurvature(NumVert(), 0); - VecDH vertGaussianCurvature(NumVert(), glm::two_pi()); - VecDH vertArea(NumVert(), 0); - VecDH degree(NumVert(), 0); - auto policy = autoPolicy(NumTri()); - for_each( - policy, countAt(0), countAt(NumTri()), - CurvatureAngles({vertMeanCurvature.ptrD(), vertGaussianCurvature.ptrD(), - vertArea.ptrD(), degree.ptrD(), halfedge_.cptrD(), - vertPos_.cptrD(), faceNormal_.cptrD()})); - for_each_n(policy, - zip(vertMeanCurvature.begin(), vertGaussianCurvature.begin(), - vertArea.begin(), degree.begin()), - NumVert(), NormalizeCurvature()); - result.minMeanCurvature = reduce( - policy, vertMeanCurvature.begin(), vertMeanCurvature.end(), - std::numeric_limits::infinity(), thrust::minimum()); - result.maxMeanCurvature = reduce( - policy, vertMeanCurvature.begin(), vertMeanCurvature.end(), - -std::numeric_limits::infinity(), thrust::maximum()); - result.minGaussianCurvature = reduce( - policy, vertGaussianCurvature.begin(), vertGaussianCurvature.end(), - std::numeric_limits::infinity(), thrust::minimum()); - result.maxGaussianCurvature = reduce( - policy, vertGaussianCurvature.begin(), vertGaussianCurvature.end(), - -std::numeric_limits::infinity(), thrust::maximum()); - result.vertMeanCurvature.insert(result.vertMeanCurvature.end(), - vertMeanCurvature.begin(), - vertMeanCurvature.end()); - result.vertGaussianCurvature.insert(result.vertGaussianCurvature.end(), - vertGaussianCurvature.begin(), - vertGaussianCurvature.end()); - return result; -} - -/** - * Calculates the bounding box of the entire manifold, which is stored - * internally to short-cut Boolean operations and to serve as the precision - * range for Morton code calculation. Ignores NaNs. - */ -void Manifold::Impl::CalculateBBox() { - auto policy = autoPolicy(NumVert()); - bBox_.min = reduce( - policy, vertPos_.begin(), vertPos_.end(), - glm::vec3(std::numeric_limits::infinity()), PosMin()); - bBox_.max = reduce( - policy, vertPos_.begin(), vertPos_.end(), - glm::vec3(-std::numeric_limits::infinity()), PosMax()); -} - -/** - * Determines if all verts are finite. Checking just the bounding box dimensions - * is insufficient as it ignores NaNs. - */ -bool Manifold::Impl::IsFinite() const { - auto policy = autoPolicy(NumVert()); - return transform_reduce(policy, vertPos_.begin(), vertPos_.end(), - FiniteVert(), true, - thrust::logical_and()); -} - -/** - * Checks that the input triVerts array has all indices inside bounds of the - * vertPos_ array. - */ -bool Manifold::Impl::IsIndexInBounds(const VecDH& triVerts) const { - auto policy = autoPolicy(triVerts.size()); - glm::ivec2 minmax = transform_reduce( - policy, triVerts.begin(), triVerts.end(), MakeMinMax(), - glm::ivec2(std::numeric_limits::max(), - std::numeric_limits::min()), - MinMax()); - - return minmax[0] >= 0 && minmax[1] < NumVert(); -} -} // namespace manifold diff --git a/IfcPlusPlus/src/external/manifold/src/sdf/CMakeLists.txt b/IfcPlusPlus/src/external/manifold/src/sdf/CMakeLists.txt deleted file mode 100644 index b4f3b5877..000000000 --- a/IfcPlusPlus/src/external/manifold/src/sdf/CMakeLists.txt +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright 2022 The Manifold Authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -project(sdf) - -add_library(${PROJECT_NAME} INTERFACE) - -target_include_directories(${PROJECT_NAME} - INTERFACE - ${PROJECT_SOURCE_DIR}/include -) - -target_link_libraries(${PROJECT_NAME} INTERFACE utilities) \ No newline at end of file diff --git a/IfcPlusPlus/src/external/manifold/src/sdf/include/sdf.h b/IfcPlusPlus/src/external/manifold/src/sdf/include/sdf.h deleted file mode 100644 index 9821c8d4e..000000000 --- a/IfcPlusPlus/src/external/manifold/src/sdf/include/sdf.h +++ /dev/null @@ -1,367 +0,0 @@ -// Copyright 2022 The Manifold Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include "hashtable.h" -#include "public.h" -#include "utils.h" -#include "vec_dh.h" - -namespace { -using namespace manifold; -__host__ __device__ Uint64 identity(Uint64 x) { return x; } - -__host__ __device__ int Next3(int i) { - constexpr glm::ivec3 next3(1, 2, 0); - return next3[i]; -} - -__host__ __device__ int Prev3(int i) { - constexpr glm::ivec3 prev3(2, 0, 1); - return prev3[i]; -} - -__host__ __device__ glm::ivec3 TetTri0(int i) { - constexpr glm::ivec3 tetTri0[16] = {{-1, -1, -1}, // - {0, 3, 4}, // - {0, 1, 5}, // - {1, 5, 3}, // - {1, 4, 2}, // - {1, 0, 3}, // - {2, 5, 0}, // - {5, 3, 2}, // - {2, 3, 5}, // - {0, 5, 2}, // - {3, 0, 1}, // - {2, 4, 1}, // - {3, 5, 1}, // - {5, 1, 0}, // - {4, 3, 0}, // - {-1, -1, -1}}; - return tetTri0[i]; -} - -__host__ __device__ glm::ivec3 TetTri1(int i) { - constexpr glm::ivec3 tetTri1[16] = {{-1, -1, -1}, // - {-1, -1, -1}, // - {-1, -1, -1}, // - {3, 4, 1}, // - {-1, -1, -1}, // - {3, 2, 1}, // - {0, 4, 2}, // - {-1, -1, -1}, // - {-1, -1, -1}, // - {2, 4, 0}, // - {1, 2, 3}, // - {-1, -1, -1}, // - {1, 4, 3}, // - {-1, -1, -1}, // - {-1, -1, -1}, // - {-1, -1, -1}}; - return tetTri1[i]; -} - -__host__ __device__ glm::ivec4 Neighbors(int i) { - constexpr glm::ivec4 neighbors[7] = {{0, 0, 0, 1}, // - {1, 0, 0, 0}, // - {0, 1, 0, 0}, // - {0, 0, 1, 0}, // - {-1, 0, 0, 1}, // - {0, -1, 0, 1}, // - {0, 0, -1, 1}}; - return neighbors[i]; -} - -__host__ __device__ Uint64 SpreadBits3(Uint64 v) { - v = v & 0x1fffff; - v = (v | v << 32) & 0x1f00000000ffff; - v = (v | v << 16) & 0x1f0000ff0000ff; - v = (v | v << 8) & 0x100f00f00f00f00f; - v = (v | v << 4) & 0x10c30c30c30c30c3; - v = (v | v << 2) & 0x1249249249249249; - return v; -} - -__host__ __device__ Uint64 SqueezeBits3(Uint64 v) { - v = v & 0x1249249249249249; - v = (v ^ v >> 2) & 0x10c30c30c30c30c3; - v = (v ^ v >> 4) & 0x100f00f00f00f00f; - v = (v ^ v >> 8) & 0x1f0000ff0000ff; - v = (v ^ v >> 16) & 0x1f00000000ffff; - v = (v ^ v >> 32) & 0x1fffff; - return v; -} - -// This is a modified 3D MortonCode, where the xyz code is shifted by one bit -// and the w bit is added as the least significant. This allows 21 bits per x, -// y, and z channel and 1 for w, filling the 64 bit total. -__host__ __device__ Uint64 MortonCode(const glm::ivec4& index) { - return static_cast(index.w) | (SpreadBits3(index.x) << 1) | - (SpreadBits3(index.y) << 2) | (SpreadBits3(index.z) << 3); -} - -__host__ __device__ glm::ivec4 DecodeMorton(Uint64 code) { - glm::ivec4 index; - index.x = SqueezeBits3(code >> 1); - index.y = SqueezeBits3(code >> 2); - index.z = SqueezeBits3(code >> 3); - index.w = code & 0x1u; - return index; -} - -struct GridVert { - float distance = NAN; - int edgeVerts[7] = {-1, -1, -1, -1, -1, -1, -1}; - - __host__ __device__ int Inside() const { return distance > 0 ? 1 : -1; } - - __host__ __device__ int NeighborInside(int i) const { - return Inside() * (edgeVerts[i] < 0 ? 1 : -1); - } -}; - -template -struct ComputeVerts { - glm::vec3* vertPos; - int* vertIndex; - HashTableD gridVerts; - const Func sdf; - const glm::vec3 origin; - const glm::ivec3 gridSize; - const glm::vec3 spacing; - const float level; - - inline __host__ __device__ glm::vec3 Position(glm::ivec4 gridIndex) const { - return origin + - spacing * (glm::vec3(gridIndex) + (gridIndex.w == 1 ? 0.0f : -0.5f)); - } - - inline __host__ __device__ float BoundedSDF(glm::ivec4 gridIndex) const { - const float d = sdf(Position(gridIndex)) - level; - - const glm::ivec3 xyz(gridIndex); - const bool onLowerBound = glm::any(glm::lessThanEqual(xyz, glm::ivec3(0))); - const bool onUpperBound = glm::any(glm::greaterThanEqual(xyz, gridSize)); - const bool onHalfBound = - gridIndex.w == 1 && glm::any(glm::greaterThanEqual(xyz, gridSize - 1)); - if (onLowerBound || onUpperBound || onHalfBound) return glm::min(d, 0.0f); - - return d; - } - - inline __host__ __device__ void operator()(Uint64 mortonCode) { - if (gridVerts.Full()) return; - - const glm::ivec4 gridIndex = DecodeMorton(mortonCode); - - if (glm::any(glm::greaterThan(glm::ivec3(gridIndex), gridSize))) return; - - const glm::vec3 position = Position(gridIndex); - - GridVert gridVert; - gridVert.distance = BoundedSDF(gridIndex); - - bool keep = false; - // These seven edges are uniquely owned by this gridVert; any of them - // which intersect the surface create a vert. - for (int i = 0; i < 7; ++i) { - glm::ivec4 neighborIndex = gridIndex + Neighbors(i); - if (neighborIndex.w == 2) { - neighborIndex += 1; - neighborIndex.w = 0; - } - const float val = BoundedSDF(neighborIndex); - if ((val > 0) == (gridVert.distance > 0)) continue; - keep = true; - - const int idx = AtomicAdd(*vertIndex, 1); - vertPos[idx] = - (val * position - gridVert.distance * Position(neighborIndex)) / - (val - gridVert.distance); - gridVert.edgeVerts[i] = idx; - } - - if (keep) gridVerts.Insert(mortonCode, gridVert); - } -}; - -struct BuildTris { - glm::ivec3* triVerts; - int* triIndex; - const HashTableD gridVerts; - - __host__ __device__ void CreateTri(const glm::ivec3& tri, - const int edges[6]) { - if (tri[0] < 0) return; - int idx = AtomicAdd(*triIndex, 1); - triVerts[idx] = {edges[tri[0]], edges[tri[1]], edges[tri[2]]}; - } - - __host__ __device__ void CreateTris(const glm::ivec4& tet, - const int edges[6]) { - const int i = (tet[0] > 0 ? 1 : 0) + (tet[1] > 0 ? 2 : 0) + - (tet[2] > 0 ? 4 : 0) + (tet[3] > 0 ? 8 : 0); - CreateTri(TetTri0(i), edges); - CreateTri(TetTri1(i), edges); - } - - __host__ __device__ void operator()(int idx) { - Uint64 basekey = gridVerts.KeyAt(idx); - if (basekey == kOpen) return; - - const GridVert& base = gridVerts.At(idx); - const glm::ivec4 baseIndex = DecodeMorton(basekey); - - glm::ivec4 leadIndex = baseIndex; - if (leadIndex.w == 0) - leadIndex.w = 1; - else { - leadIndex += 1; - leadIndex.w = 0; - } - - // This GridVert is in charge of the 6 tetrahedra surrounding its edge in - // the (1,1,1) direction (edge 0). - glm::ivec4 tet(base.NeighborInside(0), base.Inside(), -2, -2); - glm::ivec4 thisIndex = baseIndex; - thisIndex.x += 1; - - GridVert thisVert = gridVerts[MortonCode(thisIndex)]; - - tet[2] = base.NeighborInside(1); - for (const int i : {0, 1, 2}) { - thisIndex = leadIndex; - --thisIndex[Prev3(i)]; - // MortonCodes take unsigned input, so check for negatives, given the - // decrement. - GridVert nextVert = thisIndex[Prev3(i)] < 0 - ? GridVert() - : gridVerts[MortonCode(thisIndex)]; - tet[3] = base.NeighborInside(Prev3(i) + 4); - - const int edges1[6] = {base.edgeVerts[0], - base.edgeVerts[i + 1], - nextVert.edgeVerts[Next3(i) + 4], - nextVert.edgeVerts[Prev3(i) + 1], - thisVert.edgeVerts[i + 4], - base.edgeVerts[Prev3(i) + 4]}; - thisVert = nextVert; - CreateTris(tet, edges1); - - thisIndex = baseIndex; - ++thisIndex[Next3(i)]; - nextVert = gridVerts[MortonCode(thisIndex)]; - tet[2] = tet[3]; - tet[3] = base.NeighborInside(Next3(i) + 1); - - const int edges2[6] = {base.edgeVerts[0], - edges1[5], - thisVert.edgeVerts[i + 4], - nextVert.edgeVerts[Next3(i) + 4], - edges1[3], - base.edgeVerts[Next3(i) + 1]}; - thisVert = nextVert; - CreateTris(tet, edges2); - - tet[2] = tet[3]; - } - } -}; -} // namespace - -namespace manifold { - -/** @addtogroup Core - * @{ - */ - -/** - * Constructs a level-set Mesh from the input Signed-Distance Function (SDF). - * This uses a form of Marching Tetrahedra (akin to Marching Cubes, but better - * for manifoldness). Instead of using a cubic grid, it uses a body-centered - * cubic grid (two shifted cubic grids). This means if your function's interior - * exceeds the given bounds, you will see a kind of egg-crate shape closing off - * the manifold, which is due to the underlying grid. - * - * @param sdf The signed-distance functor, containing this function signature: - * `__host__ __device__ float operator()(glm::vec3 point)`, which returns the - * signed distance of a given point in R^3. Positive values are inside, - * negative outside. The `__host__ __device__` is only needed if you compile for - * CUDA. If you are using a large grid, the advantage of a GPU speedup is - * quite significant. - * @param bounds An axis-aligned box that defines the extent of the grid. - * @param edgeLength Approximate maximum edge length of the triangles in the - * final result. This affects grid spacing, and hence has a strong effect on - * performance. - * @param level You can inset your Mesh by using a positive value, or outset - * it with a negative value. - * @return Mesh This class does not depend on Manifold, so it just returns a - * Mesh, but it is guaranteed to be manifold and so can always be used as - * input to the Manifold constructor for further operations. - */ -template -inline Mesh LevelSet(Func sdf, Box bounds, float edgeLength, float level = 0) { - Mesh out; - - const glm::vec3 dim = bounds.Size(); - const float maxDim = std::max(dim[0], std::max(dim[1], dim[2])); - const glm::ivec3 gridSize(dim / edgeLength); - const glm::vec3 spacing = dim / (glm::vec3(gridSize)); - - const Uint64 maxMorton = MortonCode(glm::ivec4(gridSize + 1, 1)); - const auto policy = autoPolicy(maxMorton); - - int tableSize = glm::min( - 2 * maxMorton, static_cast(10 * glm::pow(maxMorton, 0.667))); - HashTable gridVerts(tableSize); - VecDH vertPos(gridVerts.Size() * 7); - - while (1) { - VecDH index(1, 0); - for_each_n( - policy, countAt(0), maxMorton + 1, - ComputeVerts({vertPos.ptrD(), index.ptrD(), gridVerts.D(), sdf, - bounds.min, gridSize + 1, spacing, level})); - - if (gridVerts.Full()) { // Resize HashTable - const glm::vec3 lastVert = vertPos[index[0] - 1]; - const Uint64 lastMorton = - MortonCode(glm::ivec4((lastVert - bounds.min) / spacing, 1)); - const float ratio = static_cast(maxMorton) / lastMorton; - if (ratio > 1000) // do not trust the ratio if it is too large - tableSize *= 2; - else - tableSize *= ratio; - gridVerts = HashTable(tableSize); - vertPos = VecDH(gridVerts.Size() * 7); - } else { // Success - vertPos.resize(index[0]); - break; - } - } - - VecDH triVerts(gridVerts.Entries() * 12); // worst case - - VecDH index(1, 0); - for_each_n(policy, countAt(0), gridVerts.Size(), - BuildTris({triVerts.ptrD(), index.ptrD(), gridVerts.D()})); - triVerts.resize(index[0]); - - out.vertPos.insert(out.vertPos.end(), vertPos.begin(), vertPos.end()); - out.triVerts.insert(out.triVerts.end(), triVerts.begin(), triVerts.end()); - return out; -} -/** @} */ -} // namespace manifold diff --git a/IfcPlusPlus/src/external/manifold/src/shared.h b/IfcPlusPlus/src/external/manifold/src/shared.h deleted file mode 100644 index bf774b192..000000000 --- a/IfcPlusPlus/src/external/manifold/src/shared.h +++ /dev/null @@ -1,195 +0,0 @@ -// Copyright 2021 The Manifold Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include "par.h" -#include "utils.h" -#include "vec_dh.h" - -namespace manifold { - -/** @addtogroup Private - * @{ - */ -__host__ __device__ inline glm::vec3 SafeNormalize(glm::vec3 v) { - v = glm::normalize(v); - return glm::isfinite(v.x) ? v : glm::vec3(0); -} - -__host__ __device__ inline int NextHalfedge(int current) { - ++current; - if (current % 3 == 0) current -= 3; - return current; -} - -__host__ __device__ inline glm::vec3 UVW(int vert, - const glm::vec3* barycentric) { - glm::vec3 uvw(0.0f); - if (vert < 0) { - uvw[vert + 3] = 1; - } else { - uvw = barycentric[vert]; - } - return uvw; -} - -/** - * By using the closest axis-aligned projection to the normal instead of a - * projection along the normal, we avoid introducing any rounding error. - */ -__host__ __device__ inline glm::mat3x2 GetAxisAlignedProjection( - glm::vec3 normal) { - glm::vec3 absNormal = glm::abs(normal); - float xyzMax; - glm::mat2x3 projection; - if (absNormal.z > absNormal.x && absNormal.z > absNormal.y) { - projection = glm::mat2x3(1.0f, 0.0f, 0.0f, // - 0.0f, 1.0f, 0.0f); - xyzMax = normal.z; - } else if (absNormal.y > absNormal.x) { - projection = glm::mat2x3(0.0f, 0.0f, 1.0f, // - 1.0f, 0.0f, 0.0f); - xyzMax = normal.y; - } else { - projection = glm::mat2x3(0.0f, 1.0f, 0.0f, // - 0.0f, 0.0f, 1.0f); - xyzMax = normal.x; - } - if (xyzMax < 0) projection[0] *= -1.0f; - return glm::transpose(projection); -} - -__host__ __device__ inline glm::vec3 GetBarycentric(const glm::vec3& v, - const glm::mat3& triPos, - float precision) { - const glm::mat3 edges(triPos[2] - triPos[1], triPos[0] - triPos[2], - triPos[1] - triPos[0]); - const glm::vec3 d2(glm::dot(edges[0], edges[0]), glm::dot(edges[1], edges[1]), - glm::dot(edges[2], edges[2])); - int longside = d2[0] > d2[1] && d2[0] > d2[2] ? 0 : d2[1] > d2[2] ? 1 : 2; - const glm::vec3 crossP = glm::cross(edges[0], edges[1]); - const float area2 = glm::dot(crossP, crossP); - const float tol2 = precision * precision; - const float vol = glm::dot(crossP, v - triPos[2]); - if (vol * vol > area2 * tol2) return glm::vec3(NAN); - - if (d2[longside] < tol2) { // point - return glm::vec3(1, 0, 0); - } else if (area2 > d2[longside] * tol2) { // triangle - glm::vec3 uvw(0); - for (int i : {0, 1, 2}) { - int j = i + 1; - if (j > 2) j -= 3; - uvw[i] = glm::dot(glm::cross(edges[i], v - triPos[j]), crossP); - } - uvw /= (uvw[0] + uvw[1] + uvw[2]); - return uvw; - } else { // line - int nextside = longside + 1; - if (nextside > 2) nextside -= 3; - const float alpha = - glm::dot(v - triPos[nextside], edges[longside]) / d2[longside]; - glm::vec3 uvw(0); - uvw[longside] = 0; - uvw[nextside++] = 1 - alpha; - if (nextside > 2) nextside -= 3; - uvw[nextside] = alpha; - return uvw; - } -} - -/** - * The fundamental component of the halfedge data structure used for storing and - * operating on the Manifold. - */ -struct Halfedge { - int startVert, endVert; - int pairedHalfedge; - int face; - __host__ __device__ bool IsForward() const { return startVert < endVert; } - __host__ __device__ bool operator<(const Halfedge& other) const { - return startVert == other.startVert ? endVert < other.endVert - : startVert < other.startVert; - } -}; - -/** - * This is a temporary edge structure which only stores edges forward and - * references the halfedge it was created from. - */ -struct TmpEdge { - int first, second, halfedgeIdx; - - __host__ __device__ TmpEdge() {} - __host__ __device__ TmpEdge(int start, int end, int idx) { - first = glm::min(start, end); - second = glm::max(start, end); - halfedgeIdx = idx; - } - - __host__ __device__ bool operator<(const TmpEdge& other) const { - return first == other.first ? second < other.second : first < other.first; - } -}; -/** @} */ - -struct Halfedge2Tmp { - __host__ __device__ void operator()( - thrust::tuple inout) { - const Halfedge& halfedge = thrust::get<1>(inout); - int idx = thrust::get<2>(inout); - if (!halfedge.IsForward()) idx = -1; - - thrust::get<0>(inout) = TmpEdge(halfedge.startVert, halfedge.endVert, idx); - } -}; - -struct TmpInvalid { - __host__ __device__ bool operator()(const TmpEdge& edge) { - return edge.halfedgeIdx < 0; - } -}; - -VecDH inline CreateTmpEdges(const VecDH& halfedge) { - VecDH edges(halfedge.size()); - for_each_n(autoPolicy(edges.size()), - zip(edges.begin(), halfedge.begin(), countAt(0)), edges.size(), - Halfedge2Tmp()); - int numEdge = - remove_if( - autoPolicy(edges.size()), edges.begin(), edges.end(), TmpInvalid()) - - edges.begin(); - ASSERT(numEdge == halfedge.size() / 2, topologyErr, "Not oriented!"); - edges.resize(numEdge); - return edges; -} - -struct ReindexEdge { - const TmpEdge* edges; - - __host__ __device__ void operator()(int& edge) { - edge = edges[edge].halfedgeIdx; - } -}; - -#ifdef MANIFOLD_DEBUG -inline std::ostream& operator<<(std::ostream& stream, const Halfedge& edge) { - return stream << "startVert = " << edge.startVert - << ", endVert = " << edge.endVert - << ", pairedHalfedge = " << edge.pairedHalfedge - << ", face = " << edge.face; -} -#endif -} // namespace manifold diff --git a/IfcPlusPlus/src/external/manifold/src/smoothing.cpp b/IfcPlusPlus/src/external/manifold/src/smoothing.cpp deleted file mode 100644 index 89d1ff47c..000000000 --- a/IfcPlusPlus/src/external/manifold/src/smoothing.cpp +++ /dev/null @@ -1,525 +0,0 @@ -// Copyright 2021 The Manifold Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -#include "impl.h" -#include "par.h" - -namespace { -using namespace manifold; - -__host__ __device__ glm::vec3 OrthogonalTo(glm::vec3 in, glm::vec3 ref) { - in -= glm::dot(in, ref) * ref; - return in; -} - -/** - * The total number of verts if a triangle is subdivided naturally such that - * each edge has edgeVerts verts along it (edgeVerts >= -1). - */ -__host__ __device__ int VertsPerTri(int edgeVerts) { - return (edgeVerts * edgeVerts + edgeVerts) / 2; -} - -struct Barycentric { - int tri; - glm::vec3 uvw; -}; - -struct ReindexHalfedge { - int* half2Edge; - - __host__ __device__ void operator()(thrust::tuple in) { - const int edge = thrust::get<0>(in); - const int halfedge = thrust::get<1>(in).halfedgeIdx; - - half2Edge[halfedge] = edge; - } -}; - -struct EdgeVerts { - glm::vec3* vertPos; - const int startIdx; - const int n; - - __host__ __device__ void operator()(thrust::tuple in) { - int edge = thrust::get<0>(in); - TmpEdge edgeVerts = thrust::get<1>(in); - - float invTotal = 1.0f / n; - for (int i = 1; i < n; ++i) - vertPos[startIdx + (n - 1) * edge + i - 1] = - (float(n - i) * vertPos[edgeVerts.first] + - float(i) * vertPos[edgeVerts.second]) * - invTotal; - } -}; - -struct InteriorVerts { - glm::vec3* vertPos; - glm::vec3* uvw; - BaryRef* triBary; - glm::vec3* uvwNew; - BaryRef* triBaryNew; - const glm::vec3* uvwOld; - const int startIdx; - const int n; - const Halfedge* halfedge; - - __host__ __device__ void operator()(thrust::tuple in) { - const int tri = thrust::get<0>(in); - const BaryRef baryOld = thrust::get<1>(in); - - glm::mat3 uvwOldTri; - for (int i : {0, 1, 2}) uvwOldTri[i] = UVW(baryOld.vertBary[i], uvwOld); - - const float invTotal = 1.0f / n; - int posTri = tri * n * n; - int posBary = tri * VertsPerTri(n + 1); - int pos = startIdx + tri * VertsPerTri(n - 2); - for (int i = 0; i <= n; ++i) { - for (int j = 0; j <= n - i; ++j) { - const int k = n - i - j; - const float u = invTotal * j; - const float v = invTotal * k; - const float w = invTotal * i; - const int first = posBary; - uvw[posBary] = {u, v, w}; - uvwNew[posBary] = uvwOldTri * uvw[posBary]; - ++posBary; - if (j == n - i) continue; - - // The three retained verts are denoted by their index - 3. uvw entries - // are added for them out of laziness of indexing only. - const int a = (k == n) ? -2 : first; - const int b = (i == n - 1) ? -1 : first + n - i + 1; - const int c = (j == n - 1) ? -3 : first + 1; - glm::ivec3 vertBary(c, a, b); - triBary[posTri] = {-1, -1, tri, vertBary}; - triBaryNew[posTri++] = {baryOld.meshID, baryOld.originalID, baryOld.tri, - vertBary}; - if (j < n - 1 - i) { - int d = b + 1; // d cannot be a retained vert - vertBary = {b, d, c}; - triBary[posTri] = {-1, -1, tri, vertBary}; - triBaryNew[posTri++] = {baryOld.meshID, baryOld.originalID, - baryOld.tri, vertBary}; - } - - if (i == 0 || j == 0 || k == 0) continue; - - vertPos[pos++] = u * vertPos[halfedge[3 * tri].startVert] + // - v * vertPos[halfedge[3 * tri + 1].startVert] + // - w * vertPos[halfedge[3 * tri + 2].startVert]; - } - } - } -}; - -struct SplitTris { - glm::ivec3* triVerts; - const Halfedge* halfedge; - const int* half2Edge; - const int edgeIdx; - const int triIdx; - const int n; - - __host__ __device__ int EdgeVert(int i, int inHalfedge) const { - bool forward = halfedge[inHalfedge].IsForward(); - int edge = forward ? half2Edge[inHalfedge] - : half2Edge[halfedge[inHalfedge].pairedHalfedge]; - return edgeIdx + (n - 1) * edge + (forward ? i - 1 : n - 1 - i); - } - - __host__ __device__ int TriVert(int i, int j, int tri) const { - --i; - --j; - int m = n - 2; - int vertsPerTri = (m * m + m) / 2; - int vertOffset = (i * (2 * m - i + 1)) / 2 + j; - return triIdx + vertsPerTri * tri + vertOffset; - } - - __host__ __device__ int Vert(int i, int j, int tri) const { - bool edge0 = i == 0; - bool edge1 = j == 0; - bool edge2 = j == n - i; - if (edge0) { - if (edge1) - return halfedge[3 * tri + 1].startVert; - else if (edge2) - return halfedge[3 * tri].startVert; - else - return EdgeVert(n - j, 3 * tri); - } else if (edge1) { - if (edge2) - return halfedge[3 * tri + 2].startVert; - else - return EdgeVert(i, 3 * tri + 1); - } else if (edge2) - return EdgeVert(j, 3 * tri + 2); - else - return TriVert(i, j, tri); - } - - __host__ __device__ void operator()(int tri) { - int pos = n * n * tri; - for (int i = 0; i < n; ++i) { - for (int j = 0; j < n - i; ++j) { - int a = Vert(i, j, tri); - int b = Vert(i + 1, j, tri); - int c = Vert(i, j + 1, tri); - triVerts[pos++] = glm::ivec3(c, a, b); - if (j < n - 1 - i) { - int d = Vert(i + 1, j + 1, tri); - triVerts[pos++] = glm::ivec3(b, d, c); - } - } - } - } -}; - -struct SmoothBezier { - const glm::vec3* vertPos; - const glm::vec3* triNormal; - const glm::vec3* vertNormal; - const Halfedge* halfedge; - - __host__ __device__ void operator()( - thrust::tuple inOut) { - glm::vec4& tangent = thrust::get<0>(inOut); - const Halfedge edge = thrust::get<1>(inOut); - - const glm::vec3 startV = vertPos[edge.startVert]; - const glm::vec3 edgeVec = vertPos[edge.endVert] - startV; - const glm::vec3 edgeNormal = - (triNormal[edge.face] + triNormal[halfedge[edge.pairedHalfedge].face]) / - 2.0f; - glm::vec3 dir = glm::normalize(glm::cross(glm::cross(edgeNormal, edgeVec), - vertNormal[edge.startVert])); - - const float weight = glm::abs(glm::dot(dir, glm::normalize(edgeVec))); - // Quadratic weighted bezier for circular interpolation - const glm::vec4 bz2 = - weight * - glm::vec4(startV + dir * glm::length(edgeVec) / (2 * weight), 1.0f); - // Equivalent cubic weighted bezier - const glm::vec4 bz3 = glm::mix(glm::vec4(startV, 1.0f), bz2, 2 / 3.0f); - // Convert from homogeneous form to geometric form - tangent = glm::vec4(glm::vec3(bz3) / bz3.w - startV, bz3.w); - } -}; - -struct TriBary2Vert { - Barycentric* vertBary; - int* lock; - const glm::vec3* uvw; - const Halfedge* halfedge; - - __host__ __device__ void operator()(thrust::tuple in) { - const BaryRef baryRef = thrust::get<0>(in); - const int tri = thrust::get<1>(in); - - for (int i : {0, 1, 2}) { - int vert = halfedge[3 * tri + i].startVert; - if (AtomicAdd(lock[vert], 1) != 0) continue; - vertBary[vert] = {baryRef.tri, UVW(baryRef.vertBary[i], uvw)}; - } - } -}; - -struct InterpTri { - const Halfedge* halfedge; - const glm::vec4* halfedgeTangent; - const glm::vec3* vertPos; - - __host__ __device__ glm::vec4 Homogeneous(glm::vec4 v) const { - v.x *= v.w; - v.y *= v.w; - v.z *= v.w; - return v; - } - - __host__ __device__ glm::vec4 Homogeneous(glm::vec3 v) const { - return glm::vec4(v, 1.0f); - } - - __host__ __device__ glm::vec3 HNormalize(glm::vec4 v) const { - return glm::vec3(v) / v.w; - } - - __host__ __device__ glm::vec4 Bezier(glm::vec3 point, - glm::vec4 tangent) const { - return Homogeneous(glm::vec4(point, 0) + tangent); - } - - __host__ __device__ glm::mat2x4 CubicBezier2Linear(glm::vec4 p0, glm::vec4 p1, - glm::vec4 p2, glm::vec4 p3, - float x) const { - glm::mat2x4 out; - glm::vec4 p12 = glm::mix(p1, p2, x); - out[0] = glm::mix(glm::mix(p0, p1, x), p12, x); - out[1] = glm::mix(p12, glm::mix(p2, p3, x), x); - return out; - } - - __host__ __device__ glm::vec3 BezierPoint(glm::mat2x4 points, float x) const { - return HNormalize(glm::mix(points[0], points[1], x)); - } - - __host__ __device__ glm::vec3 BezierTangent(glm::mat2x4 points) const { - return glm::normalize(HNormalize(points[1]) - HNormalize(points[0])); - } - - __host__ __device__ void operator()( - thrust::tuple inOut) { - glm::vec3& pos = thrust::get<0>(inOut); - const int tri = thrust::get<1>(inOut).tri; - const glm::vec3 uvw = thrust::get<1>(inOut).uvw; - - glm::vec4 posH(0); - const glm::mat3 corners = {vertPos[halfedge[3 * tri].startVert], - vertPos[halfedge[3 * tri + 1].startVert], - vertPos[halfedge[3 * tri + 2].startVert]}; - - for (const int i : {0, 1, 2}) { - if (uvw[i] == 1) { - pos = glm::vec3(corners[i]); - return; - } - } - - const glm::mat3x4 tangentR = {halfedgeTangent[3 * tri], - halfedgeTangent[3 * tri + 1], - halfedgeTangent[3 * tri + 2]}; - const glm::mat3x4 tangentL = { - halfedgeTangent[halfedge[3 * tri + 2].pairedHalfedge], - halfedgeTangent[halfedge[3 * tri].pairedHalfedge], - halfedgeTangent[halfedge[3 * tri + 1].pairedHalfedge]}; - - for (const int i : {0, 1, 2}) { - const int j = (i + 1) % 3; - const int k = (i + 2) % 3; - const float x = uvw[k] / (1 - uvw[i]); - - const glm::mat2x4 bez = CubicBezier2Linear( - Homogeneous(corners[j]), Bezier(corners[j], tangentR[j]), - Bezier(corners[k], tangentL[k]), Homogeneous(corners[k]), x); - const glm::vec3 end = BezierPoint(bez, x); - const glm::vec3 tangent = BezierTangent(bez); - - const glm::vec3 jBitangent = SafeNormalize(OrthogonalTo( - glm::vec3(tangentL[j]), SafeNormalize(glm::vec3(tangentR[j])))); - const glm::vec3 kBitangent = SafeNormalize(OrthogonalTo( - glm::vec3(tangentR[k]), -SafeNormalize(glm::vec3(tangentL[k])))); - const glm::vec3 normal = SafeNormalize( - glm::cross(glm::mix(jBitangent, kBitangent, x), tangent)); - const glm::vec3 delta = OrthogonalTo( - glm::mix(glm::vec3(tangentL[j]), glm::vec3(tangentR[k]), x), normal); - const float deltaW = glm::mix(tangentL[j].w, tangentR[k].w, x); - - const glm::mat2x4 bez1 = CubicBezier2Linear( - Homogeneous(end), Homogeneous(glm::vec4(end + delta, deltaW)), - Bezier(corners[i], glm::mix(tangentR[i], tangentL[i], x)), - Homogeneous(corners[i]), uvw[i]); - const glm::vec3 p = BezierPoint(bez1, uvw[i]); - float w = uvw[j] * uvw[j] * uvw[k] * uvw[k]; - posH += Homogeneous(glm::vec4(p, w)); - } - pos = HNormalize(posH); - } -}; -} // namespace - -namespace manifold { - -/** - * Calculates halfedgeTangent_, allowing the manifold to be refined and - * smoothed. The tangents form weighted cubic Beziers along each edge. This - * function creates circular arcs where possible (minimizing maximum curvature), - * constrained to the vertex normals. Where sharpenedEdges are specified, the - * tangents are shortened that intersect the sharpened edge, concentrating the - * curvature there, while the tangents of the sharp edges themselves are aligned - * for continuity. - */ -void Manifold::Impl::CreateTangents( - const std::vector& sharpenedEdges) { - const int numHalfedge = halfedge_.size(); - halfedgeTangent_.resize(numHalfedge); - - for_each_n(autoPolicy(numHalfedge), - zip(halfedgeTangent_.begin(), halfedge_.cbegin()), numHalfedge, - SmoothBezier({vertPos_.cptrD(), faceNormal_.cptrD(), - vertNormal_.cptrD(), halfedge_.cptrD()})); - - if (!sharpenedEdges.empty()) { - const VecDH& triBary = meshRelation_.triBary; - - // sharpenedEdges are referenced to the input Mesh, but the triangles have - // been sorted in creating the Manifold, so the indices are converted using - // meshRelation_. - std::vector oldHalfedge2New(halfedge_.size()); - for (int tri = 0; tri < NumTri(); ++tri) { - int oldTri = triBary[tri].tri; - for (int i : {0, 1, 2}) oldHalfedge2New[3 * oldTri + i] = 3 * tri + i; - } - - using Pair = std::pair; - // Fill in missing pairs with default smoothness = 1. - std::map edges; - for (Smoothness edge : sharpenedEdges) { - if (edge.smoothness == 1) continue; - edge.halfedge = oldHalfedge2New[edge.halfedge]; - int pair = halfedge_[edge.halfedge].pairedHalfedge; - if (edges.find(pair) == edges.end()) { - edges[edge.halfedge] = {edge, {pair, 1}}; - } else { - edges[pair].second = edge; - } - } - - std::map> vertTangents; - for (const auto& value : edges) { - const Pair edge = value.second; - vertTangents[halfedge_[edge.first.halfedge].startVert].push_back(edge); - vertTangents[halfedge_[edge.second.halfedge].startVert].push_back( - {edge.second, edge.first}); - } - - VecDH& tangent = halfedgeTangent_; - for (const auto& value : vertTangents) { - const std::vector& vert = value.second; - // Sharp edges that end are smooth at their terminal vert. - if (vert.size() == 1) continue; - if (vert.size() == 2) { // Make continuous edge - const int first = vert[0].first.halfedge; - const int second = vert[1].first.halfedge; - const glm::vec3 newTangent = glm::normalize(glm::vec3(tangent[first]) - - glm::vec3(tangent[second])); - tangent[first] = - glm::vec4(glm::length(glm::vec3(tangent[first])) * newTangent, - tangent[first].w); - tangent[second] = - glm::vec4(-glm::length(glm::vec3(tangent[second])) * newTangent, - tangent[second].w); - - auto SmoothHalf = [&](int first, int last, float smoothness) { - int current = NextHalfedge(halfedge_[first].pairedHalfedge); - while (current != last) { - const float cosBeta = glm::dot( - newTangent, glm::normalize(glm::vec3(tangent[current]))); - const float factor = - (1 - smoothness) * cosBeta * cosBeta + smoothness; - tangent[current] = glm::vec4(factor * glm::vec3(tangent[current]), - tangent[current].w); - current = NextHalfedge(halfedge_[current].pairedHalfedge); - } - }; - - SmoothHalf(first, second, - (vert[0].second.smoothness + vert[1].first.smoothness) / 2); - SmoothHalf(second, first, - (vert[1].second.smoothness + vert[0].first.smoothness) / 2); - - } else { // Sharpen vertex uniformly - float smoothness = 0; - for (const Pair& pair : vert) { - smoothness += pair.first.smoothness; - smoothness += pair.second.smoothness; - } - smoothness /= 2 * vert.size(); - - const int start = vert[0].first.halfedge; - int current = start; - do { - tangent[current] = glm::vec4(smoothness * glm::vec3(tangent[current]), - tangent[current].w); - current = NextHalfedge(halfedge_[current].pairedHalfedge); - } while (current != start); - } - } - } -} - -/** - * Split each edge into n pieces and sub-triangulate each triangle accordingly. - * This function doesn't run Finish(), as that is expensive and it'll need to be - * run after the new vertices have moved, which is a likely scenario after - * refinement (smoothing). - */ -Manifold::Impl::MeshRelationD Manifold::Impl::Subdivide(int n) { - if (n < 2) return meshRelation_; - faceNormal_.resize(0); - vertNormal_.resize(0); - int numVert = NumVert(); - int numEdge = NumEdge(); - int numTri = NumTri(); - // Append new verts - int vertsPerEdge = n - 1; - int triVertStart = numVert + numEdge * vertsPerEdge; - vertPos_.resize(triVertStart + numTri * VertsPerTri(n - 2)); - - MeshRelationD relation; - relation.barycentric.resize(numTri * VertsPerTri(n + 1)); - relation.triBary.resize(n * n * numTri); - MeshRelationD oldMeshRelation = std::move(meshRelation_); - meshRelation_.barycentric.resize(relation.barycentric.size()); - meshRelation_.triBary.resize(relation.triBary.size()); - meshRelation_.originalID = oldMeshRelation.originalID; - - VecDH edges = CreateTmpEdges(halfedge_); - VecDH half2Edge(2 * numEdge); - auto policy = autoPolicy(numEdge); - for_each_n(policy, zip(countAt(0), edges.begin()), numEdge, - ReindexHalfedge({half2Edge.ptrD()})); - for_each_n(policy, zip(countAt(0), edges.begin()), numEdge, - EdgeVerts({vertPos_.ptrD(), numVert, n})); - for_each_n( - policy, zip(countAt(0), oldMeshRelation.triBary.begin()), numTri, - InteriorVerts({vertPos_.ptrD(), relation.barycentric.ptrD(), - relation.triBary.ptrD(), meshRelation_.barycentric.ptrD(), - meshRelation_.triBary.ptrD(), - oldMeshRelation.barycentric.cptrD(), triVertStart, n, - halfedge_.ptrD()})); - // Create sub-triangles - VecDH triVerts(n * n * numTri); - for_each_n(policy, countAt(0), numTri, - SplitTris({triVerts.ptrD(), halfedge_.cptrD(), half2Edge.cptrD(), - numVert, triVertStart, n})); - CreateHalfedges(triVerts); - return relation; -} - -void Manifold::Impl::Refine(int n) { - Manifold::Impl old = *this; - MeshRelationD relation = Subdivide(n); - - if (old.halfedgeTangent_.size() == old.halfedge_.size()) { - VecDH vertBary(NumVert()); - VecDH lock(NumVert(), 0); - auto policy = autoPolicy(NumTri()); - for_each_n(policy, zip(relation.triBary.begin(), countAt(0)), NumTri(), - TriBary2Vert({vertBary.ptrD(), lock.ptrD(), - relation.barycentric.cptrD(), halfedge_.cptrD()})); - - for_each_n(policy, zip(vertPos_.begin(), vertBary.begin()), NumVert(), - InterpTri({old.halfedge_.cptrD(), old.halfedgeTangent_.cptrD(), - old.vertPos_.cptrD()})); - } - - halfedgeTangent_.resize(0); - Finish(); -} -} // namespace manifold diff --git a/IfcPlusPlus/src/external/manifold/src/sort.cpp b/IfcPlusPlus/src/external/manifold/src/sort.cpp deleted file mode 100644 index 954c8f721..000000000 --- a/IfcPlusPlus/src/external/manifold/src/sort.cpp +++ /dev/null @@ -1,359 +0,0 @@ -// Copyright 2021 The Manifold Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -#include "impl.h" -#include "par.h" - -namespace { -using namespace manifold; - -constexpr uint32_t kNoCode = 0xFFFFFFFFu; - -struct Extrema : public thrust::binary_function { - __host__ __device__ void MakeForward(Halfedge& a) { - if (!a.IsForward()) { - int tmp = a.startVert; - a.startVert = a.endVert; - a.endVert = tmp; - } - } - - __host__ __device__ int MaxOrMinus(int a, int b) { - return glm::min(a, b) < 0 ? -1 : glm::max(a, b); - } - - __host__ __device__ Halfedge operator()(Halfedge a, Halfedge b) { - MakeForward(a); - MakeForward(b); - a.startVert = glm::min(a.startVert, b.startVert); - a.endVert = glm::max(a.endVert, b.endVert); - a.face = MaxOrMinus(a.face, b.face); - a.pairedHalfedge = MaxOrMinus(a.pairedHalfedge, b.pairedHalfedge); - return a; - } -}; - -__host__ __device__ uint32_t SpreadBits3(uint32_t v) { - v = 0xFF0000FFu & (v * 0x00010001u); - v = 0x0F00F00Fu & (v * 0x00000101u); - v = 0xC30C30C3u & (v * 0x00000011u); - v = 0x49249249u & (v * 0x00000005u); - return v; -} - -__host__ __device__ uint32_t MortonCode(glm::vec3 position, Box bBox) { - // Unreferenced vertices are marked NaN, and this will sort them to the end - // (the Morton code only uses the first 30 of 32 bits). - if (isnan(position.x)) return kNoCode; - - glm::vec3 xyz = (position - bBox.min) / (bBox.max - bBox.min); - xyz = glm::min(glm::vec3(1023.0f), glm::max(glm::vec3(0.0f), 1024.0f * xyz)); - uint32_t x = SpreadBits3(static_cast(xyz.x)); - uint32_t y = SpreadBits3(static_cast(xyz.y)); - uint32_t z = SpreadBits3(static_cast(xyz.z)); - return x * 4 + y * 2 + z; -} - -struct Morton { - const Box bBox; - - __host__ __device__ void operator()( - thrust::tuple inout) { - glm::vec3 position = thrust::get<1>(inout); - thrust::get<0>(inout) = MortonCode(position, bBox); - } -}; - -struct FaceMortonBox { - const Halfedge* halfedge; - const glm::vec3* vertPos; - const Box bBox; - - __host__ __device__ void operator()( - thrust::tuple inout) { - uint32_t& mortonCode = thrust::get<0>(inout); - Box& faceBox = thrust::get<1>(inout); - int face = thrust::get<2>(inout); - - // Removed tris are marked by all halfedges having pairedHalfedge = -1, and - // this will sort them to the end (the Morton code only uses the first 30 of - // 32 bits). - if (halfedge[3 * face].pairedHalfedge < 0) { - mortonCode = kNoCode; - return; - } - - glm::vec3 center(0.0f); - - for (const int i : {0, 1, 2}) { - const glm::vec3 pos = vertPos[halfedge[3 * face + i].startVert]; - center += pos; - faceBox.Union(pos); - } - center /= 3; - - mortonCode = MortonCode(center, bBox); - } -}; - -struct Reindex { - const int* indexInv; - - __host__ __device__ void operator()(Halfedge& edge) { - if (edge.startVert < 0) return; - edge.startVert = indexInv[edge.startVert]; - edge.endVert = indexInv[edge.endVert]; - } -}; - -template -void Permute(VecDH& inOut, const VecDH& new2Old) { - VecDH tmp(std::move(inOut)); - inOut.resize(new2Old.size()); - gather(autoPolicy(new2Old.size()), new2Old.begin(), new2Old.end(), - tmp.begin(), inOut.begin()); -} - -template void Permute(VecDH&, const VecDH&); -template void Permute(VecDH&, const VecDH&); - -struct ReindexFace { - Halfedge* halfedge; - glm::vec4* halfedgeTangent; - const Halfedge* oldHalfedge; - const glm::vec4* oldHalfedgeTangent; - const int* faceNew2Old; - const int* faceOld2New; - - __host__ __device__ void operator()(int newFace) { - const int oldFace = faceNew2Old[newFace]; - for (const int i : {0, 1, 2}) { - const int oldEdge = 3 * oldFace + i; - Halfedge edge = oldHalfedge[oldEdge]; - edge.face = newFace; - const int pairedFace = edge.pairedHalfedge / 3; - const int offset = edge.pairedHalfedge - 3 * pairedFace; - edge.pairedHalfedge = 3 * faceOld2New[pairedFace] + offset; - const int newEdge = 3 * newFace + i; - halfedge[newEdge] = edge; - if (oldHalfedgeTangent != nullptr) { - halfedgeTangent[newEdge] = oldHalfedgeTangent[oldEdge]; - } - } - } -}; - -} // namespace - -namespace manifold { - -/** - * Once halfedge_ has been filled in, this function can be called to create the - * rest of the internal data structures. This function also removes the verts - * and halfedges flagged for removal (NaN verts and -1 halfedges). - */ -void Manifold::Impl::Finish() { - if (halfedge_.size() == 0) return; - - CalculateBBox(); - SetPrecision(precision_); - if (!bBox_.IsFinite()) { - // Decimated out of existence - early out. - MarkFailure(Error::MANIFOLD_NO_ERROR); - return; - } - - SortVerts(); - VecDH faceBox; - VecDH faceMorton; - GetFaceBoxMorton(faceBox, faceMorton); - SortFaces(faceBox, faceMorton); - if (halfedge_.size() == 0) return; - - ASSERT(halfedge_.size() % 6 == 0, topologyErr, - "Not an even number of faces after sorting faces!"); - -#ifdef MANIFOLD_DEBUG - Halfedge extrema = {0, 0, 0, 0}; - extrema = reduce(autoPolicy(halfedge_.size()), halfedge_.begin(), - halfedge_.end(), extrema, Extrema()); -#endif - - ASSERT(extrema.startVert >= 0, topologyErr, "Vertex index is negative!"); - ASSERT(extrema.endVert < NumVert(), topologyErr, - "Vertex index exceeds number of verts!"); - ASSERT(extrema.face >= 0, topologyErr, "Face index is negative!"); - ASSERT(extrema.face < NumTri(), topologyErr, - "Face index exceeds number of faces!"); - ASSERT(extrema.pairedHalfedge >= 0, topologyErr, - "Halfedge index is negative!"); - ASSERT(extrema.pairedHalfedge < 2 * NumEdge(), topologyErr, - "Halfedge index exceeds number of halfedges!"); - ASSERT(meshRelation_.triBary.size() == NumTri() || - meshRelation_.triBary.size() == 0, - logicErr, "Mesh Relation doesn't fit!"); - ASSERT(faceNormal_.size() == NumTri() || faceNormal_.size() == 0, logicErr, - "faceNormal size = " + std::to_string(faceNormal_.size()) + - ", NumTri = " + std::to_string(NumTri())); - // TODO: figure out why this has a flaky failure and then enable reading - // vertNormals from a Mesh. - // ASSERT(vertNormal_.size() == NumVert() || vertNormal_.size() == 0, - // logicErr, - // "vertNormal size = " + std::to_string(vertNormal_.size()) + - // ", NumVert = " + std::to_string(NumVert())); - - CalculateNormals(); - collider_ = Collider(faceBox, faceMorton); -} - -/** - * Sorts the vertices according to their Morton code. - */ -void Manifold::Impl::SortVerts() { - const int numVert = NumVert(); - VecDH vertMorton(numVert); - auto policy = autoPolicy(numVert); - for_each_n(policy, zip(vertMorton.begin(), vertPos_.cbegin()), numVert, - Morton({bBox_})); - - VecDH vertNew2Old(numVert); - sequence(policy, vertNew2Old.begin(), vertNew2Old.end()); - sort_by_key(policy, vertMorton.begin(), vertMorton.end(), - zip(vertPos_.begin(), vertNew2Old.begin())); - - ReindexVerts(vertNew2Old, numVert); - - // Verts were flagged for removal with NaNs and assigned kNoCode to sort - // them to the end, which allows them to be removed. - const int newNumVert = - find(policy, vertMorton.begin(), - vertMorton.end(), kNoCode) - - vertMorton.begin(); - vertPos_.resize(newNumVert); - if (vertNormal_.size() == numVert) { - Permute(vertNormal_, vertNew2Old); - vertNormal_.resize(newNumVert); - } -} - -/** - * Updates the halfedges to point to new vert indices based on a mapping, - * vertNew2Old. This may be a subset, so the total number of original verts is - * also given. - */ -void Manifold::Impl::ReindexVerts(const VecDH& vertNew2Old, - int oldNumVert) { - VecDH vertOld2New(oldNumVert); - scatter(autoPolicy(oldNumVert), countAt(0), countAt(NumVert()), - vertNew2Old.begin(), vertOld2New.begin()); - for_each(autoPolicy(oldNumVert), halfedge_.begin(), halfedge_.end(), - Reindex({vertOld2New.cptrD()})); -} - -/** - * Fills the faceBox and faceMorton input with the bounding boxes and Morton - * codes of the faces, respectively. The Morton code is based on the center of - * the bounding box. - */ -void Manifold::Impl::GetFaceBoxMorton(VecDH& faceBox, - VecDH& faceMorton) const { - faceBox.resize(NumTri()); - faceMorton.resize(NumTri()); - for_each_n(autoPolicy(NumTri()), - zip(faceMorton.begin(), faceBox.begin(), countAt(0)), NumTri(), - FaceMortonBox({halfedge_.cptrD(), vertPos_.cptrD(), bBox_})); -} - -/** - * Sorts the faces of this manifold according to their input Morton code. The - * bounding box and Morton code arrays are also sorted accordingly. - */ -void Manifold::Impl::SortFaces(VecDH& faceBox, - VecDH& faceMorton) { - VecDH faceNew2Old(NumTri()); - auto policy = autoPolicy(faceNew2Old.size()); - sequence(policy, faceNew2Old.begin(), faceNew2Old.end()); - - sort_by_key(policy, faceMorton.begin(), faceMorton.end(), - zip(faceBox.begin(), faceNew2Old.begin())); - - // Tris were flagged for removal with pairedHalfedge = -1 and assigned kNoCode - // to sort them to the end, which allows them to be removed. - const int newNumTri = - find(policy, faceMorton.begin(), - faceMorton.end(), kNoCode) - - faceMorton.begin(); - faceBox.resize(newNumTri); - faceMorton.resize(newNumTri); - faceNew2Old.resize(newNumTri); - - GatherFaces(faceNew2Old); -} - -/** - * Creates the halfedge_ vector for this manifold by copying a set of faces from - * another manifold, given by oldHalfedge. Input faceNew2Old defines the old - * faces to gather into this. - */ -void Manifold::Impl::GatherFaces(const VecDH& faceNew2Old) { - const int numTri = faceNew2Old.size(); - if (meshRelation_.triBary.size() == NumTri()) - Permute(meshRelation_.triBary, faceNew2Old); - - if (faceNormal_.size() == NumTri()) Permute(faceNormal_, faceNew2Old); - - VecDH oldHalfedge(std::move(halfedge_)); - VecDH oldHalfedgeTangent(std::move(halfedgeTangent_)); - VecDH faceOld2New(oldHalfedge.size() / 3); - auto policy = autoPolicy(numTri); - scatter(policy, countAt(0), countAt(numTri), faceNew2Old.begin(), - faceOld2New.begin()); - - halfedge_.resize(3 * numTri); - if (oldHalfedgeTangent.size() != 0) halfedgeTangent_.resize(3 * numTri); - for_each_n(policy, countAt(0), numTri, - ReindexFace({halfedge_.ptrD(), halfedgeTangent_.ptrD(), - oldHalfedge.cptrD(), oldHalfedgeTangent.cptrD(), - faceNew2Old.cptrD(), faceOld2New.cptrD()})); -} - -void Manifold::Impl::GatherFaces(const Impl& old, - const VecDH& faceNew2Old) { - const int numTri = faceNew2Old.size(); - meshRelation_.triBary.resize(numTri); - auto policy = autoPolicy(numTri); - gather(policy, faceNew2Old.begin(), faceNew2Old.end(), - old.meshRelation_.triBary.begin(), meshRelation_.triBary.begin()); - meshRelation_.barycentric = old.meshRelation_.barycentric; - - if (old.faceNormal_.size() == old.NumTri()) { - faceNormal_.resize(numTri); - gather(policy, faceNew2Old.begin(), faceNew2Old.end(), - old.faceNormal_.begin(), faceNormal_.begin()); - } - - VecDH faceOld2New(old.NumTri()); - scatter(policy, countAt(0), countAt(numTri), faceNew2Old.begin(), - faceOld2New.begin()); - - halfedge_.resize(3 * numTri); - if (old.halfedgeTangent_.size() != 0) halfedgeTangent_.resize(3 * numTri); - for_each_n(policy, countAt(0), numTri, - ReindexFace({halfedge_.ptrD(), halfedgeTangent_.ptrD(), - old.halfedge_.cptrD(), old.halfedgeTangent_.cptrD(), - faceNew2Old.cptrD(), faceOld2New.cptrD()})); -} -} // namespace manifold diff --git a/IfcPlusPlus/src/external/manifold/src/third_party/CMakeLists.txt b/IfcPlusPlus/src/external/manifold/src/third_party/CMakeLists.txt deleted file mode 100644 index 223fdedd6..000000000 --- a/IfcPlusPlus/src/external/manifold/src/third_party/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -add_subdirectory(graphlite) diff --git a/IfcPlusPlus/src/external/manifold/src/third_party/graphlite/CMakeLists.txt b/IfcPlusPlus/src/external/manifold/src/third_party/graphlite/CMakeLists.txt deleted file mode 100644 index 06cf03b7c..000000000 --- a/IfcPlusPlus/src/external/manifold/src/third_party/graphlite/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -project (graphlite) - -add_library(${PROJECT_NAME} src/connected_components.cpp) - -target_include_directories(${PROJECT_NAME} - PUBLIC ${PROJECT_SOURCE_DIR}/include -) - -target_compile_options(${PROJECT_NAME} PRIVATE ${MANIFOLD_FLAGS}) -target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_17) \ No newline at end of file diff --git a/IfcPlusPlus/src/external/manifold/src/third_party/graphlite/LICENSE.txt b/IfcPlusPlus/src/external/manifold/src/third_party/graphlite/LICENSE.txt deleted file mode 100644 index 8665808d7..000000000 --- a/IfcPlusPlus/src/external/manifold/src/third_party/graphlite/LICENSE.txt +++ /dev/null @@ -1,7 +0,0 @@ -Copyright 2021 Guohao Dou - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/IfcPlusPlus/src/external/manifold/src/third_party/graphlite/include/graph.h b/IfcPlusPlus/src/external/manifold/src/third_party/graphlite/include/graph.h deleted file mode 100644 index 658153c37..000000000 --- a/IfcPlusPlus/src/external/manifold/src/third_party/graphlite/include/graph.h +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2022 The Manifold Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once -#include "graph_lite.h" - -namespace manifold { - -typedef typename graph_lite::Graph< - int, void, void, graph_lite::EdgeDirection::UNDIRECTED, - graph_lite::MultiEdge::DISALLOWED, graph_lite::SelfLoop::DISALLOWED, - graph_lite::Map::UNORDERED_MAP, graph_lite::Container::VEC> - Graph; - -int ConnectedComponents(std::vector& components, const Graph& g); -} // namespace manifold \ No newline at end of file diff --git a/IfcPlusPlus/src/external/manifold/src/third_party/graphlite/include/graph_lite.h b/IfcPlusPlus/src/external/manifold/src/third_party/graphlite/include/graph_lite.h deleted file mode 100644 index e222a0cd0..000000000 --- a/IfcPlusPlus/src/external/manifold/src/third_party/graphlite/include/graph_lite.h +++ /dev/null @@ -1,1428 +0,0 @@ -// From https://github.com/haasdo95/graphlite commit 9cd2815e5d571a87e5b8b8ef3752e04d971f35d4 -#ifndef GSK_GRAPH_LITE_H -#define GSK_GRAPH_LITE_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// container spec -namespace graph_lite { -// ContainerGen, supposed to be container of neighbors -enum class Container { VEC, LIST, SET, UNORDERED_SET, MULTISET, UNORDERED_MULTISET }; - -// self loop permission -enum class SelfLoop { ALLOWED, DISALLOWED }; - -// multi-edge permission -enum class MultiEdge { ALLOWED, DISALLOWED }; - -// directed or undirected graph -enum class EdgeDirection { DIRECTED, UNDIRECTED }; - -// map for adj list -enum class Map { MAP, UNORDERED_MAP }; -} - -// type manipulation -namespace graph_lite::detail { -template -constexpr bool is_vector_v = - std::is_same_v>; - -template -constexpr bool is_list_v = - std::is_same_v>; - -// determine if type is map or unordered_map -template -struct is_map : std::false_type {}; -template -struct is_map> { - static constexpr bool value = - std::is_same_v>; -}; -template -constexpr bool is_map_v = is_map::value; - -template -struct is_unordered_map : std::false_type {}; -template -struct is_unordered_map< - T, std::void_t> { - static constexpr bool value = std::is_same_v< - T, std::unordered_map>; -}; -template -constexpr bool is_unordered_map_v = is_unordered_map::value; -template -constexpr bool is_either_map_v = is_map_v || is_unordered_map_v; - -// CREDIT: https://stackoverflow.com/questions/765148/how-to-remove-constness-of-const-iterator -template -typename ContainerType::iterator const_iter_to_iter(ContainerType& c, ConstIterator it) { - return c.erase(it, it); -} -// shorthand for turning const T& into T -template -struct remove_cv_ref { - using type = std::remove_cv_t>; -}; -template -using remove_cv_ref_t = typename remove_cv_ref::type; -// END OF shorthand for turning const T& into T - -// test if lhs==rhs and lhs!=rhs work -template > -struct is_eq_comparable : std::false_type {}; -template -struct is_eq_comparable() == std::declval())>> - : std::true_type {}; -template -constexpr bool is_eq_comparable_v = is_eq_comparable::value; - -// END OF test if lhs==rhs work - -// test comparability; see if a < b works -template > -struct is_comparable : std::false_type {}; -template -struct is_comparable() < std::declval())>> - : std::true_type {}; -template -constexpr bool is_comparable_v = is_comparable::value; -// END OF test comparability - -// test streamability -template > -struct is_streamable : std::false_type {}; -template -struct is_streamable() << std::declval())>> - : std::true_type {}; -template -constexpr bool is_streamable_v = is_streamable::value; -// END OF test streamability - -// test hashability -template > -struct is_std_hashable : std::false_type {}; -template -struct is_std_hashable>()(std::declval()))>> - : std::true_type {}; -template -constexpr bool is_std_hashable_v = is_std_hashable::value; -// END OF test hashability - -template -struct MultiEdgeTraits {}; -template <> -struct MultiEdgeTraits { - static constexpr MultiEdge value = MultiEdge::ALLOWED; -}; -template <> -struct MultiEdgeTraits { - static constexpr MultiEdge value = MultiEdge::ALLOWED; -}; -template <> -struct MultiEdgeTraits { - static constexpr MultiEdge value = MultiEdge::ALLOWED; -}; -template <> -struct MultiEdgeTraits { - static constexpr MultiEdge value = MultiEdge::ALLOWED; -}; -template <> -struct MultiEdgeTraits { - static constexpr MultiEdge value = MultiEdge::DISALLOWED; -}; -template <> -struct MultiEdgeTraits { - static constexpr MultiEdge value = MultiEdge::DISALLOWED; -}; - -template -struct OutIn { - T out; - T in; -}; -} - -// operation on containers -namespace graph_lite::detail::container { -template , - typename ContainerType::value_type>>> -auto insert(ContainerType& c, ValueType&& v) { - return c.insert(c.cend(), std::forward(v)); -} - -// find the first occurrence of a value -// using different find for efficiency; std::find is always linear -template && !is_list_v, bool> = true> -auto find(ContainerType& c, const ValueType& v) { - return c.find(v); -} - -template -auto find(std::vector>& c, const ValueType& v) { - return std::find_if(c.begin(), c.end(), [&v](const auto& p) { return p.first == v; }); -} -template -auto find(std::list>& c, const ValueType& v) { - return std::find_if(c.begin(), c.end(), [&v](const auto& p) { return p.first == v; }); -} - -template -auto find(const std::vector>& c, const ValueType& v) { - return std::find_if(c.begin(), c.end(), [&v](const auto& p) { return p.first == v; }); -} -template -auto find(const std::list>& c, const ValueType& v) { - return std::find_if(c.begin(), c.end(), [&v](const auto& p) { return p.first == v; }); -} - -template , bool> = true> -auto find(std::vector& c, const ValueType& v) { - return std::find(c.begin(), c.end(), v); -} - -template , bool> = true> -auto find(std::list& c, const ValueType& v) { - return std::find(c.begin(), c.end(), v); -} - -template , bool> = true> -auto find(const std::vector& c, const ValueType& v) { - return std::find(c.begin(), c.end(), v); -} - -template , bool> = true> -auto find(const std::list& c, const ValueType& v) { - return std::find(c.begin(), c.end(), v); -} -// END OF find the first occurrence of a value - -// count the occurrence of a value -template -std::enable_if_t && !is_list_v, int> count( - const ContainerType& c, const ValueType& v) { - return c.count(v); -} - -template -int count(const std::vector>& c, const ValueType& v) { - return std::count_if(c.begin(), c.end(), [&v](const auto& e) { return e.first == v; }); -} - -template -int count(const std::list>& c, const ValueType& v) { - return std::count_if(c.begin(), c.end(), [&v](const auto& e) { return e.first == v; }); -} - -template -std::enable_if_t, int> count( - const std::vector& c, const ValueType& v) { - return std::count(c.begin(), c.end(), v); -} - -template -std::enable_if_t, int> count( - const std::list& c, const ValueType& v) { - return std::count(c.begin(), c.end(), v); -} -// END OF count the occurrence of a value - -// remove all by value -// erase always erases all with value v; again, std::remove is linear -template -std::enable_if_t && !is_list_v, int> erase_all( - ContainerType& c, const ValueType& v) { - static_assert(std::is_same_v>); - return c.erase(v); -} - -template -std::enable_if_t, int> erase_all( - std::vector& c, const ValueType& v) { - size_t old_size = c.size(); - c.erase(std::remove(c.begin(), c.end(), v), c.end()); - return old_size - c.size(); -} - -template -int erase_all(std::vector>& c, const ValueType& v) { - size_t old_size = c.size(); - c.erase(std::remove_if(c.begin(), c.end(), [&v](const auto& p) { return p.first == v; }), - c.end()); - return old_size - c.size(); -} - -template -std::enable_if_t, int> erase_all( - std::list& c, const ValueType& v) { - size_t old_size = c.size(); - c.remove(v); - return old_size - c.size(); -} - -template -int erase_all(std::list>& c, const ValueType& v) { - size_t old_size = c.size(); - c.remove_if([&v](const auto& p) { return p.first == v; }); - return old_size - c.size(); -} -// END OF remove all by value - -// remove one by value or position; remove AT MOST 1 element -template -int erase_one(ContainerType& c, const ValueType& v) { - if constexpr (std::is_same_v, typename ContainerType::iterator> || - std::is_same_v, - typename ContainerType::const_iterator>) { // remove by pos - c.erase(v); - return 1; - } else { // remove by value - auto pos = find(c, v); - if (pos == c.end()) { - return 0; - } - c.erase(pos); - return 1; - } -} -// END OF remove one -} - -// mixin base classes of Graph -namespace graph_lite::detail { -// EdgePropListBase provides optional member variable edge_prop_list -template -struct EdgePropListBase { - protected: - std::list edge_prop_list; -}; -template <> -struct EdgePropListBase {}; // empty base optimization if edge prop is not needed - -// EdgeDirectionBase provides different API for directed and undirected graphs -template -struct EdgeDirectionBase {}; - -template -struct EdgeDirectionBase { // undirected graph only - template - auto neighbors(const T& node_iv) const { - const auto* self = static_cast(this); - return self->template get_neighbors_helper(node_iv); - } - template - auto neighbors(const T& node_iv) { - auto* self = static_cast(this); - return self->template get_neighbors_helper(node_iv); - } - // returns the number of neighbors of a node - template - int count_neighbors(const T& node_iv) const { - const auto* self = static_cast(this); - return self->template count_neighbors_helper(node_iv); - } - - // find a node with value tgt within the neighborhood of src - template - auto find_neighbor(const U& src_iv, V&& tgt_identifier) const { - const auto* self = static_cast(this); - return self->template find_neighbor_helper(src_iv, std::forward(tgt_identifier)); - } - template - auto find_neighbor(const U& src_iv, V&& tgt_identifier) { // non-const overload - auto* self = static_cast(this); - return self->template find_neighbor_helper(src_iv, std::forward(tgt_identifier)); - } -}; - -template -struct EdgeDirectionBase { // directed graph only - template - auto out_neighbors(const T& node_iv) const { - const auto* self = static_cast(this); - return self->template get_neighbors_helper(node_iv); - } - template - auto out_neighbors(const T& node_iv) { - auto* self = static_cast(this); - return self->template get_neighbors_helper(node_iv); - } - - template - auto in_neighbors(const T& node_iv) const { - const auto* self = static_cast(this); - return self->template get_neighbors_helper(node_iv); - } - template - auto in_neighbors(const T& node_iv) { - auto* self = static_cast(this); - return self->template get_neighbors_helper(node_iv); - } - - // returns the number of out neighbors of a node - template - int count_out_neighbors(const T& node_iv) const { - const auto* self = static_cast(this); - return self->template count_neighbors_helper(node_iv); - } - - // returns the number of out neighbors of a node - template - int count_in_neighbors(const T& node_iv) const { - const auto* self = static_cast(this); - return self->template count_neighbors_helper(node_iv); - } - - // find a node with value tgt within the out-neighborhood of src - template - auto find_out_neighbor(const U& src_iv, V&& tgt_identifier) const { - const auto* self = static_cast(this); - return self->template find_neighbor_helper(src_iv, std::forward(tgt_identifier)); - } - template - auto find_out_neighbor(const U& src_iv, V&& tgt_identifier) { // non-const overload - auto* self = static_cast(this); - return self->template find_neighbor_helper(src_iv, std::forward(tgt_identifier)); - } - - // find a node with value tgt within the in-neighborhood of src - template - auto find_in_neighbor(const U& src_iv, V&& tgt_identifier) const { - const auto* self = static_cast(this); - return self->template find_neighbor_helper(src_iv, std::forward(tgt_identifier)); - } - template - auto find_in_neighbor(const U& src_iv, V&& tgt_identifier) { // non-const overload - auto* self = static_cast(this); - return self->template find_neighbor_helper(src_iv, std::forward(tgt_identifier)); - } -}; - -// NodePropGraphBase provides different API depending on whether node prop is needed -template -struct NodePropGraphBase { - public: // this can seg fault if node_identifier is invalid... - template - const NodePropType& node_prop(const T& node_iv) const { - const auto* self = static_cast(this); - auto pos = self->find_by_iter_or_by_value(node_iv); - return pos->second.prop; - } - template - NodePropType& node_prop(const T& node_iv) { - return const_cast( - static_cast(this)->node_prop(node_iv)); - } - - template - int add_node_with_prop(NT&& new_node, NPT&&... prop) noexcept { - static_assert(std::is_same_v, typename GType::node_type>); - static_assert(std::is_constructible_v); - auto* self = static_cast(this); - if (!self->adj_list.count(new_node)) { // insert if not already existing - // this should invoke(in-place) the constructor of PropNode - self->adj_list.emplace(std::piecewise_construct, - std::forward_as_tuple(std::forward(new_node)), - std::forward_as_tuple(std::forward(prop)...)); - return 1; - } - return 0; // a no-op if already existing - } -}; -template -struct NodePropGraphBase { // no node prop - template - int add_nodes(T&& new_node) noexcept { // base case - static_assert(std::is_same_v, typename GType::node_type>); - auto* self = static_cast(this); - int old_size = self->adj_list.size(); - self->adj_list[std::forward(new_node)]; // insertion here; no-op if already existing - return self->adj_list.size() - old_size; - } - template - int add_nodes(T&& new_node, Args&&... args) noexcept { - static_assert(std::is_same_v, typename GType::node_type>); - return add_nodes(std::forward(new_node)) + add_nodes(std::forward(args)...); - } -}; - -// EdgePropGraphBase provides method "add_edge" when edge prop is not needed; -// and "add_edge_with_prop" when edge prop is needed -template -struct EdgePropGraphBase { - // extract edge property given node pair - template - EdgePropType& edge_prop(U&& source_iv, V&& target_iv) { - return const_cast( - static_cast(this)->template edge_prop( - std::forward(source_iv), std::forward(target_iv))); - } - - template - const EdgePropType& edge_prop(U&& source_iv, V&& target_iv) const { - const auto* self = static_cast(this); - const char* src_not_found_msg = "source is not found"; - const char* tgt_not_found_msg = "target is not found"; - auto find_neighbor_iv = [self, &source_iv, &target_iv]() { - auto&& tgt_val = self->unwrap_by_iter_or_by_value(std::forward(target_iv)); - if constexpr (GType::DIRECTION == EdgeDirection::UNDIRECTED) { - return self->find_neighbor(source_iv, std::forward(tgt_val)); - } else { - return self->find_out_neighbor(source_iv, std::forward(tgt_val)); - } - }; - auto find_neighbor_vi = [self, &source_iv, &target_iv]() { - auto&& src_val = self->unwrap_by_iter_or_by_value(std::forward(source_iv)); - if constexpr (GType::DIRECTION == EdgeDirection::UNDIRECTED) { - return self->find_neighbor(target_iv, std::forward(src_val)); - } else { - return self->find_in_neighbor(target_iv, std::forward(src_val)); - } - }; - // this ensures that no adj list lookup will happen if either is an iterator - if constexpr (GType::template is_iterator()) { // I & V or I & I - auto [found, pos] = find_neighbor_iv(); - if (!found) { - throw std::runtime_error(tgt_not_found_msg); - } - return pos->second.prop(); - } else { - // V & I or V & V - auto [found, pos] = find_neighbor_vi(); - if (!found) { - throw std::runtime_error(src_not_found_msg); - } - return pos->second.prop(); - } - } - - template - int add_edge_with_prop(U&& source_iv, V&& target_iv, EPT&&... prop) noexcept { - static_assert(std::is_constructible_v); - auto* self = static_cast(this); - auto src_pos = self->find_by_iter_or_by_value(source_iv); - auto tgt_pos = self->find_by_iter_or_by_value(target_iv); - if (src_pos == self->adj_list.end() || tgt_pos == self->adj_list.end()) { - if (src_pos == self->adj_list.end()) { - self->print_by_iter_or_by_value(std::cerr << "(add_edge) edge involves non-existent source", - source_iv) - << "\n"; - } - if (tgt_pos == self->adj_list.end()) { - self->print_by_iter_or_by_value(std::cerr << "(add_edge) edge involves non-existent target", - target_iv) - << "\n"; - } - return 0; - } - const typename GType::node_type& src_full = src_pos->first; - const typename GType::node_type& tgt_full = tgt_pos->first; // flesh out src and tgt - if (self->check_edge_dup(src_pos, src_full, tgt_full)) { - return 0; - } - if (self->check_self_loop(src_pos, tgt_pos, src_full)) { - return 0; - } - auto prop_pos = self->insert_edge_prop(std::forward(prop)...); - container::insert(self->get_out_neighbors(src_pos), std::make_pair(tgt_full, prop_pos)); - if (src_pos != tgt_pos || GType::DIRECTION == EdgeDirection::DIRECTED) { - container::insert(self->get_in_neighbors(tgt_pos), std::make_pair(src_full, prop_pos)); - } - ++self->num_of_edges; - return 1; - } -}; -template -struct EdgePropGraphBase { - template - int add_edge(U&& source_iv, V&& target_iv) noexcept { - auto* self = static_cast(this); - auto src_pos = self->find_by_iter_or_by_value(source_iv); - auto tgt_pos = self->find_by_iter_or_by_value(target_iv); - if (src_pos == self->adj_list.end() || tgt_pos == self->adj_list.end()) { - if (src_pos == self->adj_list.end()) { - self->print_by_iter_or_by_value(std::cerr << "(add_edge) edge involves non-existent source", - source_iv) - << "\n"; - } - if (tgt_pos == self->adj_list.end()) { - self->print_by_iter_or_by_value(std::cerr << "(add_edge) edge involves non-existent target", - target_iv) - << "\n"; - } - return 0; - } - const typename GType::node_type& src_full = src_pos->first; - const typename GType::node_type& tgt_full = tgt_pos->first; // flesh out src and tgt - if (self->check_edge_dup(src_pos, src_full, tgt_full)) { - return 0; - } - if (self->check_self_loop(src_pos, tgt_pos, src_full)) { - return 0; - } - container::insert(self->get_out_neighbors(src_pos), tgt_full); - if (src_pos != tgt_pos || GType::DIRECTION == EdgeDirection::DIRECTED) { - container::insert(self->get_in_neighbors(tgt_pos), src_full); - } - ++self->num_of_edges; - return 1; - } -}; -} - -// Graph class -namespace graph_lite { -template -class Graph : private detail::EdgePropListBase, - public detail::EdgeDirectionBase< - Graph, - direction>, - public detail::NodePropGraphBase< - Graph, - NodePropType>, - public detail::EdgePropGraphBase< - Graph, - EdgePropType> { - // friend class with CRTP base classes - friend detail::EdgeDirectionBase< - Graph, - direction>; - friend detail::NodePropGraphBase< - Graph, - NodePropType>; - friend detail::EdgePropGraphBase< - Graph, - EdgePropType>; - static_assert(std::is_same_v>, - "NodeType should not be a reference"); - static_assert(std::is_same_v>, - "NodeType should not be cv-qualified"); - static_assert(std::is_same_v> && - std::is_same_v>, - "Property types should not be references"); - static_assert(std::is_same_v> && - std::is_same_v>, - "Property types should not be cv-qualified"); - static_assert(detail::is_eq_comparable_v, - "NodeType does not support ==; implement operator=="); - static_assert(detail::is_streamable_v, - "NodeType is not streamable; implement operator<<"); - static_assert(!((neighbors_container_spec == Container::UNORDERED_SET || - neighbors_container_spec == Container::UNORDERED_MULTISET || - adj_list_spec == Map::UNORDERED_MAP) && - !detail::is_std_hashable_v), - "NodeType is not hashable"); - static_assert(!((neighbors_container_spec == Container::SET || - neighbors_container_spec == Container::MULTISET || - adj_list_spec == Map::MAP) && - !detail::is_comparable_v), - "NodeType does not support operator <"); - static_assert(!(detail::MultiEdgeTraits::value == - MultiEdge::DISALLOWED && - multi_edge == MultiEdge::ALLOWED), - "node container does not support multi-edge"); - static_assert(!((neighbors_container_spec == Container::MULTISET || - neighbors_container_spec == Container::UNORDERED_MULTISET) && - multi_edge == MultiEdge::DISALLOWED), - "disallowing multi-edge yet still using multi-set; use set/unordered_set instead"); - - public: // exposed types and constants - using node_type = NodeType; - using node_prop_type = NodePropType; - using edge_prop_type = EdgePropType; - static constexpr EdgeDirection DIRECTION = direction; - static constexpr MultiEdge MULTI_EDGE = multi_edge; - static constexpr SelfLoop SELF_LOOP = self_loop; - static constexpr Map ADJ_LIST_SPEC = adj_list_spec; - static constexpr Container NEIGHBORS_CONTAINER_SPEC = neighbors_container_spec; - - private: // type gymnastics - // handle neighbors that may have property - // PairIterator is useful only when (1) the container is VEC or LIST and (2) edge prop is needed - template - class PairIterator { // always non const, since the build-in iter can handle const - friend class Graph; - - private: - using It = typename ContainerType::iterator; - using ConstIt = typename ContainerType::const_iterator; - It it; - using VT = typename It::value_type; - using FirstType = typename VT::first_type; - using SecondType = typename VT::second_type; - - public: // mimic the iter of a std::map - using difference_type = typename It::difference_type; - using value_type = std::pair; - using reference = std::pair; - using pointer = std::pair*; - using iterator_category = std::bidirectional_iterator_tag; - PairIterator() = default; - // can be implicitly converted FROM a non-const iter - PairIterator(const It& it) : it{it} {} - // can be implicitly converted TO a const iter - // relying on the imp conv of the underlying iter - operator ConstIt() { return it; } - - friend bool operator==(const PairIterator& lhs, const PairIterator& rhs) { - return lhs.it == rhs.it; - } - friend bool operator!=(const PairIterator& lhs, const PairIterator& rhs) { - return lhs.it != rhs.it; - } - friend bool operator==(const PairIterator& lhs, const ConstIt& rhs) { return lhs.it == rhs; } - friend bool operator!=(const PairIterator& lhs, const ConstIt& rhs) { return lhs.it != rhs; } - // symmetry - friend bool operator==(const ConstIt& lhs, const PairIterator& rhs) { return rhs == lhs; } - friend bool operator!=(const ConstIt& lhs, const PairIterator& rhs) { return rhs != lhs; } - - reference operator*() const { return {std::cref(it->first), std::ref(it->second)}; } - pointer operator->() const { - std::pair* ptr = it.operator->(); - using CVT = std::pair; - static_assert(offsetof(VT, first) == offsetof(CVT, first) && - offsetof(VT, second) == offsetof(CVT, second)); - return static_cast(static_cast(ptr)); // adding constness to first - } - - PairIterator& operator++() { // prefix - ++it; - return *this; - } - PairIterator& operator--() { // prefix - --it; - return *this; - } - PairIterator operator++(int) & { // postfix - PairIterator tmp = *this; - ++(*this); - return tmp; - } - PairIterator operator--(int) & { // postfix - PairIterator tmp = *this; - --(*this); - return tmp; - } - }; - - template - struct EdgePropIterWrap { - friend class Graph; - - private: - using Iter = typename std::list::iterator; - // list iterators are NOT invalidated by insertion/removal(of others), making this possible - Iter pos; - - public: - EdgePropIterWrap() = default; - explicit EdgePropIterWrap(const Iter& pos) : pos{pos} {} - const EPT& prop() const { return *(this->pos); } - EPT& prop() { return *(this->pos); } - }; - - using NeighborType = std::conditional_t, NodeType, - std::pair>>; - // type of neighbors container; the typename NT is here only because explicit spec is not allowed - // in a class... - template - struct ContainerGen {}; - template - struct ContainerGen { - using type = std::list; - }; - template - struct ContainerGen { - using type = std::vector; - }; - template - struct ContainerGen { - using type = std::map>; - }; - template - struct ContainerGen { - using type = std::set; - }; - template - struct ContainerGen { - using type = std::multimap>; - }; - template - struct ContainerGen { - using type = std::multiset; - }; - template - struct ContainerGen { - using type = std::unordered_map>; - }; - template - struct ContainerGen { - using type = std::unordered_set; - }; - template - struct ContainerGen { - using type = std::unordered_multimap>; - }; - template - struct ContainerGen { - using type = std::unordered_multiset; - }; - - public: - using NeighborsContainerType = - typename ContainerGen::type; - - private: - using NeighborsType = - std::conditional_t>; - struct PropNode { // node with property - NodePropType prop; - NeighborsType neighbors; - PropNode() = default; // needed for map/unordered map - template - explicit PropNode(NPT&&... prop) : prop{std::forward(prop)...}, neighbors{} { - static_assert(std::is_constructible_v); - } - }; - static constexpr bool has_node_prop = ! std::is_void_v; - using AdjListValueType = std::conditional_t; - using AdjListType = - std::conditional_t, - std::unordered_map>; - - public: // iterator types - using NeighborsConstIterator = typename NeighborsContainerType::const_iterator; - - private: - template - static constexpr bool can_construct_node = - std::is_constructible_v>; - static constexpr bool has_edge_prop = !std::is_void_v; - static constexpr bool need_pair_iter = - has_edge_prop && - (neighbors_container_spec == Container::VEC || neighbors_container_spec == Container::LIST); - - public: - using NeighborsIterator = std::conditional_t< - has_edge_prop, - std::conditional_t, // make node(aka first) immutable - typename NeighborsContainerType::iterator>, // the iter for map/multi-map - // works just fine - NeighborsConstIterator>; // if no edge prop is needed, always const - static_assert(std::is_convertible_v); - using NeighborsView = std::pair; - using NeighborsConstView = std::pair; - - private: - using AdjListIterType = typename AdjListType::iterator; - using AdjListConstIterType = typename AdjListType::const_iterator; - - private: - int num_of_edges{}; - AdjListType adj_list; - - private: // iterator support - template - class Iter { - private: - template - friend class Iter; - friend class Graph; - using AdjIterT = std::conditional_t; - AdjIterT it; - - public: - Iter() = default; - Iter(AdjIterT it) : it{it} {}; - - // enables implicit conversion from non-const to const - template > - Iter(const Iter& other) : it{other.it} {} - - Iter& operator++() { // prefix - ++it; - return *this; - } - Iter operator++(int) & { // postfix - Iter tmp = *this; - ++(*this); - return tmp; - } - const NodeType& operator*() const { return it->first; } - const NodeType* operator->() const { return &(it->first); } - friend bool operator==(const Iter& lhs, const Iter& rhs) { return lhs.it == rhs.it; } - friend bool operator!=(const Iter& lhs, const Iter& rhs) { return lhs.it != rhs.it; } - }; - - public: - using Iterator = Iter; - using ConstIterator = Iter; - static_assert(std::is_convertible_v); - - Iterator begin() noexcept { return Iter(adj_list.begin()); } - Iterator end() noexcept { return Iter(adj_list.end()); } - ConstIterator begin() const noexcept { return Iter(adj_list.cbegin()); } - ConstIterator end() const noexcept { return Iter(adj_list.cend()); } - // END OF iterator support - private: // neighbor access helpers - const NeighborsContainerType& get_out_neighbors(AdjListConstIterType adj_iter) const { - if constexpr (!has_node_prop) { - if constexpr (direction == EdgeDirection::UNDIRECTED) { - return adj_iter->second; - } else { - return adj_iter->second.out; - } - } else { - if constexpr (direction == EdgeDirection::UNDIRECTED) { - return adj_iter->second.neighbors; - } else { - return adj_iter->second.neighbors.out; - } - } - } - NeighborsContainerType& get_out_neighbors(AdjListIterType adj_iter) { - return const_cast( - static_cast(this)->get_out_neighbors(adj_iter)); - } - - const NeighborsContainerType& get_in_neighbors(AdjListConstIterType adj_iter) const { - if constexpr (!has_node_prop) { - if constexpr (direction == EdgeDirection::UNDIRECTED) { - return adj_iter->second; - } else { - return adj_iter->second.in; - } - } else { - if constexpr (direction == EdgeDirection::UNDIRECTED) { - return adj_iter->second.neighbors; - } else { - return adj_iter->second.neighbors.in; - } - } - } - NeighborsContainerType& get_in_neighbors(AdjListIterType adj_iter) { - return const_cast( - static_cast(this)->get_in_neighbors(adj_iter)); - } - - // helpers for EdgeDirectionBase - template - [[nodiscard]] int count_neighbors_helper(const T& node_iv) const { - AdjListConstIterType pos = find_by_iter_or_by_value(node_iv); - if (pos == adj_list.end()) { - std::string msg = is_out ? "out" : "in"; - print_by_iter_or_by_value( - std::cerr << "(count_neighbors) counting " << msg << "-neighbors of a non-existent node", - node_iv) - << "\n"; - throw std::runtime_error("counting " + msg + "-neighbors of a non-existent node"); - } - if constexpr (is_out) { - return get_out_neighbors(pos).size(); - } else { - return get_in_neighbors(pos).size(); - } - } - - template - NeighborsConstView get_neighbors_helper(const T& node_iv) const { - AdjListConstIterType pos = find_by_iter_or_by_value(node_iv); - if (pos == adj_list.end()) { - std::string msg = is_out ? "out" : "in"; - print_by_iter_or_by_value( - std::cerr << "(neighbors) finding " << msg << "-neighbors of a non-existent node", - node_iv) - << "\n"; - throw std::runtime_error("finding " + msg + "-neighbors of a non-existent node"); - } - const NeighborsContainerType& neighbors = [ this, &pos ]() -> auto& { - if constexpr (is_out) { - return get_out_neighbors(pos); - } else { - return get_in_neighbors(pos); - } - } - (); - return {neighbors.begin(), neighbors.end()}; - } - template - NeighborsView get_neighbors_helper(const T& node_iv) { - AdjListIterType pos = find_by_iter_or_by_value(node_iv); - if (pos == adj_list.end()) { - std::string msg = is_out ? "out" : "in"; - print_by_iter_or_by_value( - std::cerr << "(neighbors) finding " << msg << "-neighbors of a non-existent node", - node_iv) - << "\n"; - throw std::runtime_error("finding " + msg + "-neighbors of a non-existent node"); - } - NeighborsContainerType& neighbors = [ this, &pos ]() -> auto& { - if constexpr (is_out) { - return get_out_neighbors(pos); - } else { - return get_in_neighbors(pos); - } - } - (); - return {neighbors.begin(), neighbors.end()}; - } - // END OF helpers for EdgeDirectionBase - - const NodeType& get_neighbor_node(const NeighborsConstIterator& nbr_pos) const { - if constexpr (has_edge_prop) { - return nbr_pos->first; - } else { - return *nbr_pos; - } - } - // END OF neighbor access helpers - private: // helpers for node search - // find a node by value - template - AdjListConstIterType find_node(const T& node_identifier) const { - static_assert(can_construct_node); - if constexpr (std::is_convertible_v) { // implicit conversion - return adj_list.find(node_identifier); - } else { // conversion has to be explicit - NodeType node{node_identifier}; - return adj_list.find(node); - } - } - template - AdjListIterType find_node(const T& node_identifier) { - return detail::const_iter_to_iter(adj_list, - static_cast(this)->find_node(node_identifier)); - } - - template - static constexpr bool is_iterator() { - return std::is_same_v> || - std::is_same_v>; - } - - template - decltype(auto) unwrap_by_iter_or_by_value(T&& iter_or_val) const { - if constexpr (is_iterator()) { - return iter_or_val.it->first; - } else { - static_assert(can_construct_node); - return std::forward(iter_or_val); // simply pass along - } - } - - // either unwrap the iterator, or find the node in adj_list - template - AdjListConstIterType find_by_iter_or_by_value(const T& iter_or_val) const { - if constexpr (is_iterator()) { // by iter - return iter_or_val.it; - } else { // by value - return find_node(iter_or_val); - } - } - template - AdjListIterType find_by_iter_or_by_value(const T& iter_or_val) { - return detail::const_iter_to_iter( - adj_list, static_cast(this)->find_by_iter_or_by_value(iter_or_val)); - } - // END OF either unwrap the iterator, or find the node in adj_list - - // helper method to provide better error messages - template - std::ostream& print_by_iter_or_by_value(std::ostream& os, const T& iter_or_val) const { - if constexpr (is_iterator()) { // by iter - return os; // no-op if by iter - } else { // by value - static_assert(can_construct_node); - os << ": " << NodeType{iter_or_val}; - return os; - } - } - - // find tgt in the neighborhood of src; returns a pair {is_found, neighbor_iterator} - template - std::pair find_neighbor_helper(const U& src_iv, - V&& tgt_identifier) const { - static_assert(can_construct_node); - AdjListConstIterType src_pos = find_by_iter_or_by_value(src_iv); - if (src_pos == adj_list.end()) { - print_by_iter_or_by_value(std::cerr << "(find_neighbor) source node not found", src_iv) - << "\n"; - throw std::runtime_error{"source node is not found"}; - } - const NeighborsContainerType& src_neighbors = [ this, &src_pos ]() -> auto& { - if constexpr (is_out) { - return get_out_neighbors(src_pos); - } else { - return get_in_neighbors(src_pos); - } - } - (); - if constexpr (std::is_same_v>) { - NeighborsConstIterator tgt_pos = detail::container::find(src_neighbors, tgt_identifier); - return {tgt_pos != src_neighbors.end(), tgt_pos}; - } else { - NeighborsConstIterator tgt_pos = - detail::container::find(src_neighbors, NodeType{std::forward(tgt_identifier)}); - return {tgt_pos != src_neighbors.end(), tgt_pos}; - } - } - template - std::pair find_neighbor_helper(const U& src_iv, V&& tgt_identifier) { - static_assert(can_construct_node); - AdjListIterType src_pos = find_by_iter_or_by_value(src_iv); - if (src_pos == adj_list.end()) { - print_by_iter_or_by_value(std::cerr << "(find_neighbor) source node not found", src_iv) - << "\n"; - throw std::runtime_error{"source node is not found"}; - } - NeighborsContainerType& src_neighbors = [ this, &src_pos ]() -> auto& { - if constexpr (is_out) { - return get_out_neighbors(src_pos); - } else { - return get_in_neighbors(src_pos); - } - } - (); - if constexpr (std::is_same_v>) { - auto tgt_pos = detail::container::find(src_neighbors, tgt_identifier); - return {tgt_pos != src_neighbors.end(), tgt_pos}; - } else { - auto tgt_pos = - detail::container::find(src_neighbors, NodeType{std::forward(tgt_identifier)}); - return {tgt_pos != src_neighbors.end(), tgt_pos}; - } - } - // END OF find tgt in the neighborhood of src; returns a pair {is_found, neighbor_iterator} - // END OF helpers for node search - public: // simple queries - [[nodiscard]] size_t size() const noexcept { return adj_list.size(); } - - [[nodiscard]] int num_edges() const noexcept { return num_of_edges; } - - template - bool has_node(const T& node_identifier) const noexcept { - auto pos = find_node(node_identifier); - return pos != adj_list.end(); - } - - // count the number of edges between src and tgt - template - int count_edges(const U& source_iv, const V& target_iv) const noexcept { - AdjListConstIterType src_pos = find_by_iter_or_by_value(source_iv); - AdjListConstIterType tgt_pos = find_by_iter_or_by_value(target_iv); - if (src_pos == adj_list.end() || tgt_pos == adj_list.end()) { - if (src_pos == adj_list.end()) { - print_by_iter_or_by_value(std::cerr << "(count_edges) source node not found", source_iv) - << "\n"; - } - if (tgt_pos == adj_list.end()) { - print_by_iter_or_by_value(std::cerr << "(count_edges) target node not found", target_iv) - << "\n"; - } - return 0; - } - return detail::container::count(get_out_neighbors(src_pos), tgt_pos->first); - } - - // find a node in the graph by value - template - ConstIterator find(const T& node_identifier) const noexcept { - AdjListConstIterType pos = find_node(node_identifier); - return ConstIterator{pos}; - } - template - Iterator find(const T& node_identifier) noexcept { - AdjListIterType pos = find_node(node_identifier); - return Iterator{pos}; - } - - private: // edge addition helpers - template - auto insert_edge_prop(EPT&&... prop) { - static_assert(has_edge_prop); - static_assert(std::is_constructible_v); - this->edge_prop_list.emplace_back(std::forward(prop)...); - return EdgePropIterWrap{ - std::prev(this->edge_prop_list.end())}; // iterator to the last element - } - - bool check_edge_dup(AdjListConstIterType src_pos, const NodeType& src_full, - const NodeType& tgt_full) const { - if constexpr (multi_edge == - MultiEdge::DISALLOWED) { // check is needed only when we disallow dup - // this catches multi-self-loop as well - const NeighborsContainerType& neighbors = get_out_neighbors(src_pos); - if (detail::container::find(neighbors, tgt_full) != neighbors.end()) { - std::cerr << "(add_edge) re-adding existing edge: (" << src_full << ", " << tgt_full - << ")\n"; - return true; - } - } - return false; - } - - bool check_self_loop(AdjListIterType src_pos, AdjListIterType tgt_pos, const NodeType& src_full) { - if constexpr (self_loop == SelfLoop::DISALLOWED) { - if (src_pos == tgt_pos) { - std::cerr << "(add_edge) adding self loop on node: " << src_full << "\n"; - return true; - } - } - return false; - } - // END OF edge addition helpers - private: // edge removal helpers - // because every edge has double entry, this method finds the correct double entry to remove - NeighborsConstIterator find_tgt_remove_pos(AdjListIterType src_pos, - NeighborsConstIterator src_remove_pos, - NeighborsContainerType& tgt_neighbors) { - if constexpr (has_edge_prop && multi_edge == MultiEdge::ALLOWED) { - auto prop_address = - &(src_remove_pos->second.prop()); // finding the corresponding double entry - auto prop_finder = [&prop_address](const auto& tgt_nbr) { - return prop_address == &(tgt_nbr.second.prop()); - }; - if constexpr (neighbors_container_spec == Container::VEC || - neighbors_container_spec == Container::LIST) { - // NeighborsContainerType is a vector/list of pairs - // linearly search for the correct entry and remove - return std::find_if(tgt_neighbors.begin(), tgt_neighbors.end(), prop_finder); - } else { - // NeighborsContainerType is a multi_map or unordered_multi_map - static_assert(neighbors_container_spec == Container::MULTISET || - neighbors_container_spec == Container::UNORDERED_MULTISET); - auto [eq_begin, eq_end] = - tgt_neighbors.equal_range(src_pos->first); // slightly optimized search - return std::find_if(eq_begin, eq_end, prop_finder); - } - } else { // either multi edge is disallowed, or we don't differentiate multi-edges - static_assert(!has_edge_prop || multi_edge == MultiEdge::DISALLOWED); - return detail::container::find(tgt_neighbors, src_pos->first); - } - } - - // this method is useful for the "remove all" operation - std::pair find_remove_range( - NeighborsContainerType& neighbors, const NodeType& node) { - static_assert(has_edge_prop); - if constexpr (neighbors_container_spec == Container::VEC || - neighbors_container_spec == Container::LIST) { - NeighborsConstIterator partition_pos = - std::partition(neighbors.begin(), neighbors.end(), - [&node](const auto& src_nbr) { return !(src_nbr.first == node); }); - return {partition_pos, neighbors.end()}; - } else { - static_assert(neighbors_container_spec == Container::MULTISET || - neighbors_container_spec == Container::UNORDERED_MULTISET); - return neighbors.equal_range(node); - } - } - // END OF edge removal helpers - public: // edge removal - // all iterators are assumed to be valid - int remove_edge(ConstIterator source_pos, NeighborsConstIterator target_nbr_pos) noexcept { - AdjListIterType src_pos = detail::const_iter_to_iter(adj_list, source_pos.it); - NeighborsContainerType& src_neighbors = get_out_neighbors(src_pos); - assert(target_nbr_pos != src_neighbors.cend()); - AdjListIterType tgt_pos = adj_list.find(get_neighbor_node(target_nbr_pos)); - assert(tgt_pos != adj_list.end()); - if constexpr (self_loop == SelfLoop::DISALLOWED) { - assert(src_pos != tgt_pos); - } - NeighborsContainerType& tgt_neighbors = get_in_neighbors(tgt_pos); - NeighborsConstIterator tgt_remove_pos = - find_tgt_remove_pos(src_pos, target_nbr_pos, tgt_neighbors); - assert(tgt_remove_pos != tgt_neighbors.end()); - if constexpr (has_edge_prop) { // need to remove edge prop, as well - this->edge_prop_list.erase(target_nbr_pos->second.pos); - } - detail::container::erase_one(src_neighbors, target_nbr_pos); - if (src_pos != tgt_pos || direction == EdgeDirection::DIRECTED) { - // when src==tgt && UNDIRECTED, there is NO double entry - detail::container::erase_one(tgt_neighbors, tgt_remove_pos); - } - --num_of_edges; - return 1; - } - - // remove all edges between source and target - template - std::enable_if_t, int> remove_edge( - const U& source_iv, const V& target_iv) noexcept { - auto src_pos = find_by_iter_or_by_value(source_iv); - auto tgt_pos = find_by_iter_or_by_value(target_iv); - if (src_pos == adj_list.end() || tgt_pos == adj_list.end()) { - if (src_pos == adj_list.end()) { - print_by_iter_or_by_value(std::cerr << "(remove_edge) edge involves non-existent node", - source_iv) - << "\n"; - } - if (tgt_pos == adj_list.end()) { - print_by_iter_or_by_value(std::cerr << "(remove_edge) edge involves non-existent node", - target_iv) - << "\n"; - } - return 0; // no-op if nodes are not found - } - const NodeType& src_full = src_pos->first; - const NodeType& tgt_full = tgt_pos->first; - if constexpr (self_loop == SelfLoop::DISALLOWED) { - if (src_pos == tgt_pos) { // we know self loop cannot exist - std::cerr << "(remove_edge) cannot remove self loop on node " << src_full - << " when self loop is not even permitted\n"; - return 0; - } - } - NeighborsContainerType& src_neighbors = get_out_neighbors(src_pos); - if constexpr (multi_edge == MultiEdge::DISALLOWED) { // remove at most 1 - NeighborsIterator src_remove_pos = detail::container::find(src_neighbors, tgt_full); - if (src_remove_pos == src_neighbors.cend()) { - std::cerr << "(remove_edge) edge (" << src_full << ", " << tgt_full << ") not found\n"; - return 0; - } - remove_edge(ConstIterator{src_pos}, src_remove_pos); - --num_of_edges; - return 1; - } else { // remove all edges between src and tgt, potentially removing no edge at all - static_assert(multi_edge == MultiEdge::ALLOWED); - static_assert(neighbors_container_spec != Container::SET && - neighbors_container_spec != Container::UNORDERED_SET); - int num_edges_removed = 0; - if constexpr (has_edge_prop) { // remove prop too - const auto [src_remove_begin, src_remove_end] = find_remove_range(src_neighbors, tgt_full); - // loop through this range to remove prop - for (auto it = src_remove_begin; it != src_remove_end; ++it) { - ++num_edges_removed; - this->edge_prop_list.erase(it->second.pos); - } - // erase this range itself - src_neighbors.erase(src_remove_begin, src_remove_end); - } else { // simply erase all - num_edges_removed = detail::container::erase_all(src_neighbors, tgt_full); - } - if (src_pos != tgt_pos || direction == EdgeDirection::DIRECTED) { - int num_tgt_removed = detail::container::erase_all(get_in_neighbors(tgt_pos), src_full); - assert(num_edges_removed == num_tgt_removed); - } - if (num_edges_removed == 0) { - std::cerr << "(remove_edge) edge (" << src_full << ", " << tgt_full << ") not found\n"; - } - num_of_edges -= num_edges_removed; - return num_edges_removed; - } - } - - private: // node removal helper - template - void purge_edge_with(AdjListIterType pos) noexcept { - const NodeType& node = pos->first; - NeighborsContainerType& neighbors = [ this, &pos ]() -> auto& { - if constexpr (OutIn) { - return get_out_neighbors(pos); - } else { - return get_in_neighbors(pos); - } - } - (); - NeighborsIterator nbr_begin = neighbors.begin(); - NeighborsIterator nbr_end = neighbors.end(); - // this loop should be enough for undirected graphs - for (auto it = nbr_begin; it != nbr_end; ++it) { - // purge edges that has to do with the to-be-removed node - AdjListIterType neighbor_pos = adj_list.find(get_neighbor_node(it)); - NeighborsContainerType& neighbors_of_neighbor = [ this, &neighbor_pos ]() -> auto& { - if constexpr (OutIn) { - return get_in_neighbors(neighbor_pos); - } else { - return get_out_neighbors(neighbor_pos); - } - } - (); - if constexpr (self_loop == SelfLoop::DISALLOWED) { - detail::container::erase_all(neighbors_of_neighbor, node); - } else { - if (neighbor_pos != pos) { // need to check for self loop - detail::container::erase_all(neighbors_of_neighbor, node); - } - } - // remove edge property if needed - if constexpr (has_edge_prop) { - this->edge_prop_list.erase(it->second.pos); - } - } - } - - public: // node removal - // we can allow removal of several nodes by iterator because erase does not invalidate other - // iterators - template - int remove_nodes(const T& node_iv) noexcept { - auto pos = find_by_iter_or_by_value(node_iv); - if (pos == adj_list.end()) { // no-op if not found - print_by_iter_or_by_value(std::cerr << "(remove_nodes) removing non-existent node", node_iv) - << "\n"; - return 0; - } - purge_edge_with(pos); // purge all edges going out of node - if constexpr (direction == EdgeDirection::DIRECTED) { - // this loop makes it work for directed graphs as well - purge_edge_with(pos); // purge all edges coming into node - } - // count purged edges - auto& out_nbrs = get_out_neighbors(pos); - int num_edges_purged = out_nbrs.size(); - if constexpr (direction == EdgeDirection::DIRECTED) { - num_edges_purged += get_in_neighbors(pos).size(); - if constexpr (self_loop == SelfLoop::ALLOWED) { // we would be double counting self-edges - num_edges_purged -= detail::container::count(out_nbrs, pos->first); - } - } - num_of_edges -= num_edges_purged; - // finally erase pos - adj_list.erase(pos); - return 1; - } - template - int remove_nodes(const T& node_iv, const Args&... args) noexcept { - return remove_nodes(node_iv) + remove_nodes(args...); - } - // END OF node removal -}; -} - -#endif // GSK_GRAPH_LITE_H diff --git a/IfcPlusPlus/src/external/manifold/src/third_party/graphlite/src/connected_components.cpp b/IfcPlusPlus/src/external/manifold/src/third_party/graphlite/src/connected_components.cpp deleted file mode 100644 index b5815eb1d..000000000 --- a/IfcPlusPlus/src/external/manifold/src/third_party/graphlite/src/connected_components.cpp +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2022 The Manifold Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -#include "graph.h" - -namespace manifold { - -int ConnectedComponents(std::vector& components, const Graph& graph) { - if (!graph.size()) { - return 0; - } - components.resize(graph.size()); - std::fill(components.begin(), components.end(), -1); - - std::deque queue; - int numComponent = 0; - for (auto it = graph.begin(); it != graph.end(); ++it) { - const int& root = *it; - if (components[root] >= 0) continue; // skip visited nodes - - // new component - components[root] = numComponent; - queue.emplace_back(root); - // traverse all connected nodes - while (!queue.empty()) { - const auto [n_begin, n_end] = graph.neighbors(queue.front()); - queue.pop_front(); - for (auto n_it = n_begin; n_it != n_end; ++n_it) { - const int& neighbor = *n_it; - if (components[neighbor] < 0) { // unvisited - components[neighbor] = numComponent; - queue.emplace_back(neighbor); - } - } - } - ++numComponent; - } - return numComponent; -} -} // namespace manifold \ No newline at end of file diff --git a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/.git-blame-ignore-revs b/IfcPlusPlus/src/external/manifold/src/third_party/thrust/.git-blame-ignore-revs deleted file mode 100644 index 68469e1f1..000000000 --- a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/.git-blame-ignore-revs +++ /dev/null @@ -1,16 +0,0 @@ -# Exclude these commits from git-blame and similar tools. -# -# To use this file, run the following command from the repo root: -# -# ``` -# $ git config blame.ignoreRevsFile .git-blame-ignore-revs -# ``` -# -# Include a brief comment with each commit added, for example: -# -# ``` -# d92d9f8baac5ec48a8f8718dd69f415a45efe372 # Initial clang-format -# ``` -# -# Only add commits that are pure formatting changes (e.g. -# clang-format version changes, etc). diff --git a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/.github/workflows/mirror-main-branch-to-master-branch.yml b/IfcPlusPlus/src/external/manifold/src/third_party/thrust/.github/workflows/mirror-main-branch-to-master-branch.yml deleted file mode 100644 index e73acf394..000000000 --- a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/.github/workflows/mirror-main-branch-to-master-branch.yml +++ /dev/null @@ -1,17 +0,0 @@ -on: - push: - branches: - - "main" - -jobs: - mirror-main-branch-to-master-branch: - name: Mirror main branch to master branch - runs-on: ubuntu-latest - steps: - - name: Mirror main branch to master branch - id: mirror - uses: google/mirror-branch-action@v1.0 - with: - source: "main" - dest: "master" - github-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/.gitignore b/IfcPlusPlus/src/external/manifold/src/third_party/thrust/.gitignore deleted file mode 100644 index a789d4e0d..000000000 --- a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -*.log -.p4config -doc/html -discrete_voronoi.pgm -*build*/ -.idea/ diff --git a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/.gitmodules b/IfcPlusPlus/src/external/manifold/src/third_party/thrust/.gitmodules deleted file mode 100644 index 1d8e604ef..000000000 --- a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "cub"] - path = dependencies/cub - url = ../cub.git diff --git a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/CHANGELOG.md b/IfcPlusPlus/src/external/manifold/src/third_party/thrust/CHANGELOG.md deleted file mode 100644 index 59517c8cd..000000000 --- a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/CHANGELOG.md +++ /dev/null @@ -1,2199 +0,0 @@ -# Thrust 1.16.0 - -## Summary - -Thrust 1.16.0 provides a new “nosync” hint for the CUDA backend, as well as -numerous bugfixes and stability improvements. - -### New `thrust::cuda::par_nosync` Execution Policy - -Most of Thrust’s parallel algorithms are fully synchronous and will block the -calling CPU thread until all work is completed. This design avoids many pitfalls -associated with asynchronous GPU programming, resulting in simpler and -less-error prone usage for new CUDA developers. Unfortunately, this improvement -in user experience comes at a performance cost that often frustrates more -experienced CUDA programmers. - -Prior to this release, the only synchronous-to-asynchronous migration path for -existing Thrust codebases involved significant refactoring, replacing calls -to `thrust` algorithms with a limited set of `future`-based `thrust::async` -algorithms or lower-level CUB kernels. The new `thrust::cuda::par_nosync` -execution policy provides a new, less-invasive entry point for asynchronous -computation. - -`par_nosync` is a hint to the Thrust execution engine that any non-essential -internal synchronizations should be skipped and that an explicit synchronization -will be performed by the caller before accessing results. - -While some Thrust algorithms require internal synchronization to safely compute -their results, many do not. For example, multiple `thrust::for_each` invocations -can be launched without waiting for earlier calls to complete: - -```cpp -// Queue three `for_each` kernels: -thrust::for_each(thrust::cuda::par_nosync, vec1.begin(), vec1.end(), Op{}); -thrust::for_each(thrust::cuda::par_nosync, vec2.begin(), vec2.end(), Op{}); -thrust::for_each(thrust::cuda::par_nosync, vec3.begin(), vec3.end(), Op{}); - -// Do other work while kernels execute: -do_something(); - -// Must explictly synchronize before accessing `for_each` results: -cudaDeviceSynchronize(); -``` - -Thanks to @fkallen for this contribution. - -## Deprecation Notices - -### CUDA Dynamic Parallelism Support - -**A future version of Thrust will remove support for CUDA Dynamic Parallelism -(CDP).** - -This will only affect calls to Thrust algorithms made from CUDA device-side code -that currently launches a kernel; such calls will instead execute sequentially -on the calling GPU thread instead of launching a device-wide kernel. - -## Breaking Changes - -- Thrust 1.14.0 included a change that aliased the `cub` namespace - to `thrust::cub`. This has caused issues with ambiguous namespaces for - projects that declare `using namespace thrust;` from the global namespace. We - recommend against this practice. -- NVIDIA/thrust#1572: Removed several unnecessary header includes. Downstream - projects may need to update their includes if they were relying on this - behavior. - -## New Features - -- NVIDIA/thrust#1568: Add `thrust::cuda::par_nosync` policy. Thanks to @fkallen - for this contribution. - -## Enhancements - -- NVIDIA/thrust#1511: Use CUB’s new `DeviceMergeSort` API and remove Thrust’s - internal implementation. -- NVIDIA/thrust#1566: Improved performance of `thrust::shuffle`. Thanks to - @djns99 for this contribution. -- NVIDIA/thrust#1584: Support user-defined `CMAKE_INSTALL_INCLUDEDIR` values in - Thrust’s CMake install rules. Thanks to @robertmaynard for this contribution. - -## Bug Fixes - -- NVIDIA/thrust#1496: Fix some issues affecting `icc` builds. -- NVIDIA/thrust#1552: Fix some collisions with the `min`/`max` macros defined - in `windows.h`. -- NVIDIA/thrust#1582: Fix issue with function type alias on 32-bit MSVC builds. -- NVIDIA/thrust#1591: Workaround issue affecting compilation with `nvc++`. -- NVIDIA/thrust#1597: Fix some collisions with the `small` macro defined - in `windows.h`. -- NVIDIA/thrust#1599, NVIDIA/thrust#1603: Fix some issues with version handling - in Thrust’s CMake packages. -- NVIDIA/thrust#1614: Clarify that scan algorithm results are non-deterministic - for pseudo-associative operators (e.g. floating-point addition). - -# Thrust 1.15.0 (NVIDIA HPC SDK 22.1, CUDA Toolkit 11.6) - -## Summary - -Thrust 1.15.0 provides numerous bugfixes, including non-numeric -`thrust::sequence` support, several MSVC-related compilation fixes, fewer -conversion warnings, `counting_iterator` initialization, and documentation -updates. - -## Deprecation Notices - -**A future version of Thrust will remove support for CUDA Dynamic Parallelism -(CDP).** - -This will only affect calls to Thrust algorithms made from CUDA device-side code -that currently launches a kernel; such calls will instead execute sequentially -on the calling GPU thread instead of launching a device-wide kernel. - -## Bug Fixes - -- NVIDIA/thrust#1507: Allow `thrust::sequence` to work with non-numeric types. - Thanks to Ben Jude (@bjude) for this contribution. -- NVIDIA/thrust#1509: Avoid macro collision when calling `max()` on MSVC. Thanks - to Thomas (@tomintheshell) for this contribution. -- NVIDIA/thrust#1514: Initialize all members in `counting_iterator`'s default - constructor. -- NVIDIA/thrust#1518: Fix `std::allocator_traits` on MSVC + C++17. -- NVIDIA/thrust#1530: Fix several `-Wconversion` warnings. Thanks to Matt - Stack (@matt-stack) for this contribution. -- NVIDIA/thrust#1539: Fixed typo in `thrust::for_each` documentation. Thanks to - Salman (@untamedImpala) for this contribution. -- NVIDIA/thrust#1548: Avoid name collision with `B0` macro in termios.h system - header. Thanks to Philip Deegan (@PhilipDeegan) for this contribution. - -# Thrust 1.14.0 (NVIDIA HPC SDK 21.9) - -## Summary - -Thrust 1.14.0 is a major release accompanying the NVIDIA HPC SDK 21.9. - -This release adds the ability to wrap the `thrust::` namespace in an external -namespace, providing a workaround for a variety of shared library linking -issues. Thrust also learned to detect when CUB's symbols are in a wrapped -namespace and properly import them. To enable this feature, use -`#define THRUST_CUB_WRAPPED_NAMESPACE foo` to wrap both Thrust and CUB in the -`foo::` namespace. See `thrust/detail/config/namespace.h` for details and more -namespace options. - -Several bugfixes are also included: The `tuple_size` and `tuple_element` helpers -now support cv-qualified types. `scan_by_key` uses less memory. -`thrust::iterator_traits` is better integrated with `std::iterator_traits`. -See below for more details and references. - -## Breaking Changes - -- Thrust 1.14.0 included a change that aliased the `cub` namespace - to `thrust::cub`. This has caused issues with ambiguous namespaces for - projects that declare `using namespace thrust;` from the global namespace. We - recommend against this practice. - -## New Features - -- NVIDIA/thrust#1464: Add preprocessor hooks that allow `thrust::` to be wrapped - in an external namespace, and support cases when CUB is wrapped in an external - namespace. - -## Bug Fixes - -- NVIDIA/thrust#1457: Support cv-qualified types in `thrust::tuple_size` and - `thrust::tuple_element`. Thanks to Jake Hemstad for this contribution. -- NVIDIA/thrust#1471: Fixed excessive memory allocation in `scan_by_key`. Thanks - to Lilo Huang for this contribution. -- NVIDIA/thrust#1476: Removed dead code from the `expand` example. Thanks to - Lilo Huang for this contribution. -- NVIDIA/thrust#1488: Fixed the path to the installed CUB headers in the CMake - `find_package` configuration files. -- NVIDIA/thrust#1491: Fallback to `std::iterator_traits` when no - `thrust::iterator_traits` specialization exists for an iterator type. Thanks - to Divye Gala for this contribution. - -# Thrust 1.13.1 (CUDA Toolkit 11.5) - -Thrust 1.13.1 is a minor release accompanying the CUDA Toolkit 11.5. - -This release provides a new hook for embedding the `thrust::` namespace inside a -custom namespace. This is intended to work around various issues related to -linking multiple shared libraries that use Thrust. The existing `CUB_NS_PREFIX` -and `CUB_NS_POSTFIX` macros already provided this capability for CUB; this -update provides a simpler mechanism that is extended to and integrated with -Thrust. Simply define `THRUST_CUB_WRAPPED_NAMESPACE` to a namespace name, and -both `thrust::` and `cub::` will be placed inside the new namespace. Using -different wrapped namespaces for each shared library will prevent issues like -those reported in NVIDIA/thrust#1401. - -## New Features - -- NVIDIA/thrust#1464: Add `THRUST_CUB_WRAPPED_NAMESPACE` hooks. - -## Bug Fixes - -- NVIDIA/thrust#1488: Fix path to installed CUB in Thrust's CMake config files. - -# Thrust 1.13.0 (NVIDIA HPC SDK 21.7) - -Thrust 1.13.0 is the major release accompanying the NVIDIA HPC SDK 21.7 release. - -Notable changes include `bfloat16` radix sort support (via `thrust::sort`) and -memory handling fixes in the `reserve` method of Thrust's vectors. -The `CONTRIBUTING.md` file has been expanded to include instructions for -building CUB as a component of Thrust, and API documentation now refers to -cppreference instead of SGI's STL reference. - -## Breaking Changes - -- NVIDIA/thrust#1459: Remove deprecated aliases `thrust::host_space_tag` and - `thrust::device_space_tag`. Use the equivalent `thrust::host_system_tag` and - `thrust::device_system_tag` instead. - -## New Features - -- NVIDIA/cub#306: Add radix-sort support for `bfloat16` in `thrust::sort`. - Thanks to Xiang Gao (@zasdfgbnm) for this contribution. -- NVIDIA/thrust#1423: `thrust::transform_iterator` now supports non-copyable - types. Thanks to Jake Hemstad (@jrhemstad) for this contribution. -- NVIDIA/thrust#1459: Introduce a new `THRUST_IGNORE_DEPRECATED_API` macro that - disables deprecation warnings on Thrust and CUB APIs. - -## Bug Fixes - -- NVIDIA/cub#277: Fixed sanitizer warnings when `thrust::sort` calls - into `cub::DeviceRadixSort`. Thanks to Andy Adinets (@canonizer) for this - contribution. -- NVIDIA/thrust#1442: Reduce extraneous comparisons in `thrust::sort`'s merge - sort implementation. -- NVIDIA/thrust#1447: Fix memory leak and avoid overallocation when - calling `reserve` on Thrust's vector containers. Thanks to Kai Germaschewski - (@germasch) for this contribution. - -## Other Enhancements - -- NVIDIA/thrust#1405: Update links to standard C++ documentations from sgi to - cppreference. Thanks to Muhammad Adeel Hussain (@AdeilH) for this - contribution. -- NVIDIA/thrust#1432: Updated build instructions in `CONTRIBUTING.md` to include - details on building CUB's test suite as part of Thrust. - -# Thrust 1.12.1 (CUDA Toolkit 11.4) - -Thrust 1.12.1 is a trivial patch release that slightly changes the phrasing of -a deprecation message. - -# Thrust 1.12.0 (NVIDIA HPC SDK 21.3) - -## Summary - -Thrust 1.12.0 is the major release accompanying the NVIDIA HPC SDK 21.3 -and the CUDA Toolkit 11.4. - -It includes a new `thrust::universal_vector`, which holds data that is -accessible from both host and device. This allows users to easily leverage -CUDA's unified memory with Thrust. -New asynchronous `thrust::async:exclusive_scan` and `inclusive_scan` algorithms -have been added, and the synchronous versions of these have been updated to -use `cub::DeviceScan` directly. -CUB radix sort for floating point types is now stable when both +0.0 and -0.0 -are present in the input. This affects some usages of `thrust::sort` and -`thrust::stable_sort`. -Many compilation warnings and subtle overflow bugs were fixed in the device -algorithms, including a long-standing bug that returned invalid temporary -storage requirements when `num_items` was close to (but not -exceeding) `INT32_MAX`. - -This release deprecates support for Clang < 7.0 and MSVC < 2019 (aka -19.20/16.0/14.20). - -## Breaking Changes - -- NVIDIA/thrust#1372: Deprecate Clang < 7 and MSVC < 2019. -- NVIDIA/thrust#1376: Standardize `thrust::scan_by_key` functors / accumulator - types. This may change the results from `scan_by_key` when input, output, and - initial value types are not the same type. - -## New Features - -- NVIDIA/thrust#1251: Add two new `thrust::async::` algorithms: `inclusive_scan` - and `exclusive_scan`. -- NVIDIA/thrust#1334: Add `thrust::universal_vector`, `universal_ptr`, - and `universal_allocator`. - -## Bug Fixes - -- NVIDIA/thrust#1347: Qualify calls to `make_reverse_iterator`. -- NVIDIA/thrust#1359: Enable stricter warning flags. This fixes several - outstanding issues: - - NVIDIA/cub#221: Overflow in `temp_storage_bytes` when `num_items` close to - (but not over) `INT32_MAX`. - - NVIDIA/cub#228: CUB uses non-standard C++ extensions that break strict - compilers. - - NVIDIA/cub#257: Warning when compiling `GridEvenShare` with unsigned - offsets. - - NVIDIA/thrust#974: Conversion warnings in `thrust::transform_reduce`. - - NVIDIA/thrust#1091: Conversion warnings in `thrust::counting_iterator`. -- NVIDIA/thrust#1373: Fix compilation error when a standard library type is - wrapped in `thrust::optional`. Thanks to Vukasin Milovanovic for this - contribution. -- NVIDIA/thrust#1388: Fix `signbit(double)` implementation on MSVC. -- NVIDIA/thrust#1389: Support building Thrust tests without CUDA enabled. - -## Other Enhancements - -- NVIDIA/thrust#1304: Use `cub::DeviceScan` to implement - `thrust::exclusive_scan` and `thrust::inclusive_scan`. -- NVIDIA/thrust#1362, NVIDIA/thrust#1370: Update smoke test naming. -- NVIDIA/thrust#1380: Fix typos in `set_operation` documentation. Thanks to - Hongyu Cai for this contribution. -- NVIDIA/thrust#1383: Include FreeBSD license in LICENSE.md for - `thrust::complex` implementation. -- NVIDIA/thrust#1384: Add missing precondition to `thrust::gather` - documentation. - -# Thrust 1.11.0 (CUDA Toolkit 11.3) - -## Summary - -Thrust 1.11.0 is a major release providing bugfixes and performance -enhancements. - -It includes a new sort algorithm that provides up to 2x more performance -from `thrust::sort` when used with certain key types and hardware. - -The new `thrust::shuffle` algorithm has been tweaked to improve the randomness -of the output. - -Our CMake package and build system continue to see improvements with -better `add_subdirectory` support, installation rules, status messages, and -other features that make Thrust easier to use from CMake projects. - -The release includes several other bugfixes and modernizations, and received -updates from 12 contributors. - -## New Features - -- NVIDIA/cub#204: New implementation for `thrust::sort` on CUDA when using - 32/64-bit numeric keys on Pascal and up (SM60+). This improved radix sort - algorithm provides up to 2x more performance. Thanks for Andy Adinets for this - contribution. -- NVIDIA/thrust#1310, NVIDIA/thrust#1312: Various tuple-related APIs have been - updated to use variadic templates. Thanks for Andrew Corrigan for these - contributions. -- NVIDIA/thrust#1297: Optionally add install rules when included with - CMake's `add_subdirectory`. Thanks to Kai Germaschewski for this contribution. - -## Bug Fixes - -- NVIDIA/thrust#1309: Fix `thrust::shuffle` to produce better quality random - distributions. Thanks to Rory Mitchell and Daniel Stokes for this - contribution. -- NVIDIA/thrust#1337: Fix compile-time regression in `transform_inclusive_scan` - and `transform_exclusive_scan`. -- NVIDIA/thrust#1306: Fix binary search `middle` calculation to avoid overflows. - Thanks to Richard Barnes for this contribution. -- NVIDIA/thrust#1314: Use `size_t` for the index type parameter - in `thrust::tuple_element`. Thanks to Andrew Corrigan for this contribution. -- NVIDIA/thrust#1329: Fix runtime error when copying an - empty `thrust::device_vector` in MSVC Debug builds. Thanks to Ben Jude for - this contribution. -- NVIDIA/thrust#1323: Fix and add test for cmake package install rules. Thanks - for Keith Kraus and Kai Germaschewski for testing and discussion. -- NVIDIA/thrust#1338: Fix GCC version checks in `thrust::detail::is_pod` - implementation. Thanks to Anatoliy Tomilov for this contribution. -- NVIDIA/thrust#1289: Partial fixes for Clang 10 as host/c++ compiler. Exposed - an nvcc bug that will be fixed in a future version of the CUDA Toolkit (NVBug - 3136307). -- NVIDIA/thrust#1272: Fix ambiguous `iter_swap` call when - using `thrust::partition` with STL containers. Thanks to Isaac Deutsch for - this contribution. -- NVIDIA/thrust#1281: Update our bundled `FindTBB.cmake` module to support - latest MSVC. -- NVIDIA/thrust#1298: Use semantic versioning rules for our CMake package's - compatibility checks. Thanks to Kai Germaschewski for this contribution. -- NVIDIA/thrust#1300: Use `FindPackageHandleStandardArgs` to print standard - status messages when our CMake package is found. Thanks to Kai Germaschewski - for this contribution. -- NVIDIA/thrust#1320: Use feature-testing instead of a language dialect check - for `thrust::remove_cvref`. Thanks to Andrew Corrigan for this contribution. -- NVIDIA/thrust#1319: Suppress GPU deprecation warnings. - -## Other Enhancements - -- NVIDIA/cub#213: Removed some tuning policies for unsupported hardware (` - specialization. - - The `thrust::intermediate_type_from_function_and_iterators` helper is no - longer needed and has been removed. -- NVIDIA/thrust#1255: Always use `cudaStreamSynchronize` instead of - `cudaDeviceSynchronize` if the execution policy has a stream attached to it. - Thanks to Rong Ou for this contribution. -- NVIDIA/thrust#1201: Tests for correct handling of legacy and per-thread - default streams. - Thanks to Rong Ou for this contribution. - -## Bug Fixes - -- NVIDIA/thrust#1260: Fix `thrust::transform_inclusive_scan` with heterogeneous - types. - Thanks to Rong Ou for this contribution. -- NVIDIA/thrust#1258, NVC++ FS #28463: Ensure the CUDA radix sort backend - synchronizes before returning; otherwise, copies from temporary storage will - race with destruction of said temporary storage. -- NVIDIA/thrust#1264: Evaluate `CUDA_CUB_RET_IF_FAIL` macro argument only once. - Thanks to Jason Lowe for this contribution. -- NVIDIA/thrust#1262: Add missing `` header. -- NVIDIA/thrust#1250: Restore some `THRUST_DECLTYPE_RETURNS` macros in async - test implementations. -- NVIDIA/thrust#1249: Use `std::iota` in `CUDATestDriver::target_devices`. - Thanks to Michael Francis for this contribution. -- NVIDIA/thrust#1244: Check for macro collisions with system headers during - header testing. -- NVIDIA/thrust#1224: Remove unnecessary SFINAE contexts from asynchronous - algorithms. -- NVIDIA/thrust#1190: Make `out_of_memory_recovery` test trigger faster. -- NVIDIA/thrust#1187: Elminate superfluous iterators specific to the CUDA - backend. -- NVIDIA/thrust#1181: Various fixes for GoUDA. - Thanks to Andrei Tchouprakov for this contribution. -- NVIDIA/thrust#1178, NVIDIA/thrust#1229: Use transparent functionals in - placeholder expressions, fixing issues with `thrust::device_reference` and - placeholder expressions and `thrust::find` with asymmetric equality - operators. -- NVIDIA/thrust#1153: Switch to placement new instead of assignment to - construct items in uninitialized memory. - Thanks to Hugh Winkler for this contribution. -- NVIDIA/thrust#1050: Fix compilation of asynchronous algorithms when RDC is - enabled. -- NVIDIA/thrust#1042: Correct return type of - `thrust::detail::predicate_to_integral` from `bool` to `IntegralType`. - Thanks to Andreas Hehn for this contribution. -- NVIDIA/thrust#1009: Avoid returning uninitialized allocators. - Thanks to Zhihao Yuan for this contribution. -- NVIDIA/thrust#990: Add missing `` include to - ``. - Thanks to Robert Maynard for this contribution. -- NVIDIA/thrust#966: Fix spurious MSVC conversion with loss of data warning in - sort algorithms. - Thanks to Zhihao Yuan for this contribution. -- Add more metadata to mock specializations for testing iterator in - `testing/copy.cu`. -- Add missing include to shuffle unit test. -- Specialize `thrust::wrapped_function` for `void` return types because MSVC is - not a fan of the pattern `return static_cast(expr);`. -- Replace deprecated `tbb/tbb_thread.h` with ``. -- Fix overcounting of initial value in TBB scans. -- Use `thrust::advance` instead of `+=` for generic iterators. -- Wrap the OMP flags in `-Xcompiler` for NVCC -- Extend `ASSERT_STATIC_ASSERT` skip for the OMP backend. -- Add missing header caught by `tbb.cuda` configs. -- Fix "unsafe API" warnings in examples on MSVC: `s/fopen/fstream/` -- Various C++17 fixes. - -# Thrust 1.9.10-1 (NVIDIA HPC SDK 20.7, CUDA Toolkit 11.1) - -## Summary - -Thrust 1.9.10-1 is the minor release accompanying the NVIDIA HPC SDK 20.7 release - and the CUDA Toolkit 11.1 release. - -## Bug Fixes - -- #1214, NVBug 200619442: Stop using `std::allocator` APIs deprecated in C++17. -- #1216, NVBug 200540293: Make `thrust::optional` work with Clang when used - with older libstdc++. -- #1207, NVBug 200618218: Don't force C++14 with older compilers that don't - support it. -- #1218: Wrap includes of `` and `` to avoid circular - inclusion with NVC++. - -# Thrust 1.9.10 (NVIDIA HPC SDK 20.5) - -## Summary - -Thrust 1.9.10 is the release accompanying the NVIDIA HPC SDK 20.5 release. -It adds CMake support for compilation with NVC++ and a number of minor bug fixes - for NVC++. -It also adds CMake `find_package` support, which replaces the broken 3rd-party - legacy `FindThrust.cmake` script. -C++03, C++11, GCC < 5, Clang < 6, and MSVC < 2017 are now deprecated. -Starting with the upcoming 1.10.0 release, C++03 support will be dropped - entirely. - -## Breaking Changes - -- #1082: Thrust now checks that it is compatible with the version of CUB found - in your include path, generating an error if it is not. - If you are using your own version of CUB, it may be too old. - It is recommended to simply delete your own version of CUB and use the - version of CUB that comes with Thrust. -- #1089: C++03 and C++11 are deprecated. - Using these dialects will generate a compile-time warning. - These warnings can be suppressed by defining - `THRUST_IGNORE_DEPRECATED_CPP_DIALECT` (to suppress C++03 and C++11 - deprecation warnings) or `THRUST_IGNORE_DEPRECATED_CPP11` (to suppress C++11 - deprecation warnings). - Suppression is only a short term solution. - We will be dropping support for C++03 in the 1.10.0 release and C++11 in the - near future. -- #1089: GCC < 5, Clang < 6, and MSVC < 2017 are deprecated. - Using these compilers will generate a compile-time warning. - These warnings can be suppressed by defining - `THRUST_IGNORE_DEPRECATED_COMPILER`. - Suppression is only a short term solution. - We will be dropping support for these compilers in the near future. - -## New Features - -- #1130: CMake `find_package` support. - This is significant because there is a legacy `FindThrust.cmake` script - authored by a third party in widespread use in the community which has a - bug in how it parses Thrust version numbers which will cause it to - incorrectly parse 1.9.10. - This script only handles the first digit of each part of the Thrust version - number correctly: for example, Thrust 17.17.17 would be interpreted as - Thrust 1.1.1701717. - You can find directions for using the new CMake `find_package` support and - migrating away from the legacy `FindThrust.cmake` [here](https://github.com/NVIDIA/thrust/blob/main/thrust/cmake/README.md) -- #1129: Added `thrust::detail::single_device_tls_caching_allocator`, a - convenient way to get an MR caching allocator for device memory, which is - used by NVC++. - -## Other Enhancements - -- #1129: Refactored RDC handling in CMake to be a global option and not create - two targets for each example and test. - -## Bug Fixes - -- #1129: Fix the legacy `thrust::return_temporary_buffer` API to support - passing a size. - This was necessary to enable usage of Thrust caching MR allocators with - synchronous Thrust algorithms. - This change has allowed NVC++’s C++17 Parallel Algorithms implementation to - switch to use Thrust caching MR allocators for device temporary storage, - which gives a 2x speedup on large multi-GPU systems such as V100 and A100 - DGX where `cudaMalloc` is very slow. -- #1128: Respect `CUDA_API_PER_THREAD_DEFAULT_STREAM`. - Thanks to Rong Ou for this contribution. -- #1131: Fix the one-policy overload of `thrust::async::copy` to not copy the - policy, resolving use-afer-move issues. -- #1145: When cleaning up type names in `unittest::base_class_name`, only call - `std::string::replace` if we found the substring we are looking to replace. -- #1139: Don't use `cxx::__demangle` in NVC++. -- #1102: Don't use `thrust::detail::normal_distribution_nvcc` for Feta because - it uses `erfcinv`, a non-standard function that Feta doesn't have. - -# Thrust 1.9.9 (CUDA Toolkit 11.0) - -## Summary - -Thrust 1.9.9 adds support for NVC++, which uses Thrust to implement - GPU-accelerated C++17 Parallel Algorithms. -`thrust::zip_function` and `thrust::shuffle` were also added. -C++03, C++11, GCC < 5, Clang < 6, and MSVC < 2017 are now deprecated. -Starting with the upcoming 1.10.0 release, C++03 support will be dropped - entirely. -All other deprecated platforms will be dropped in the near future. - -## Breaking Changes - -- #1082: Thrust now checks that it is compatible with the version of CUB found - in your include path, generating an error if it is not. - If you are using your own version of CUB, it may be too old. - It is recommended to simply delete your own version of CUB and use the - version of CUB that comes with Thrust. -- #1089: C++03 and C++11 are deprecated. - Using these dialects will generate a compile-time warning. - These warnings can be suppressed by defining - `THRUST_IGNORE_DEPRECATED_CPP_DIALECT` (to suppress C++03 and C++11 - deprecation warnings) or `THRUST_IGNORE_DEPRECATED_CPP_11` (to suppress C++11 - deprecation warnings). - Suppression is only a short term solution. - We will be dropping support for C++03 in the 1.10.0 release and C++11 in the - near future. -- #1089: GCC < 5, Clang < 6, and MSVC < 2017 are deprecated. - Using these compilers will generate a compile-time warning. - These warnings can be suppressed by defining - `THRUST_IGNORE_DEPRECATED_COMPILER`. - Suppression is only a short term solution. - We will be dropping support for these compilers in the near future. - -## New Features - -- #1086: Support for NVC++ aka "Feta". - The most significant change is in how we use `__CUDA_ARCH__`. - Now, there are four macros that must be used: - - `THRUST_IS_DEVICE_CODE`, which should be used in an `if` statement around - device-only code. - - `THRUST_INCLUDE_DEVICE_CODE`, which should be used in an `#if` preprocessor - directive inside of the `if` statement mentioned in the prior bullet. - - `THRUST_IS_HOST_CODE`, which should be used in an `if` statement around - host-only code. - - `THRUST_INCLUDE_HOST_CODE`, which should be used in an `#if` preprocessor - directive inside of the `if` statement mentioned in the prior bullet. -- #1085: `thrust::shuffle`. - Thanks to Rory Mitchell for this contribution. -- #1029: `thrust::zip_function`, a facility for zipping functions that take N - parameters instead of a tuple of N parameters as `thrust::zip_iterator` - does. - Thanks to Ben Jude for this contribution. -- #1068: `thrust::system::cuda::managed_memory_pointer`, a universal memory - strongly typed pointer compatible with the ISO C++ Standard Library. - -## Other Enhancements - -- #1029: Thrust is now built and tested with NVCC warnings treated as errors. -- #1029: MSVC C++11 support. -- #1029: `THRUST_DEPRECATED` abstraction for generating compile-time - deprecation warning messages. -- #1029: `thrust::pointer::pointer_to(reference)`. -- #1070: Unit test for `thrust::inclusive_scan` with a user defined types. - Thanks to Conor Hoekstra for this contribution. - -## Bug Fixes - -- #1088: Allow `thrust::replace` to take functions that have non-`const` - `operator()`. -- #1094: Add missing `constexpr` to `par_t` constructors. - Thanks to Patrick Stotko for this contribution. -- #1077: Remove `__device__` from CUDA MR-based device allocators to fix - obscure "host function called from host device function" warning that occurs - when you use the new Thrust MR-based allocators. -- #1029: Remove inconsistently-used `THRUST_BEGIN`/`END_NS` macros. -- #1029: Fix C++ dialect detection on newer MSVC. -- #1029 Use `_Pragma`/`__pragma` instead of `#pragma` in macros. -- #1029: Replace raw `__cplusplus` checks with the appropriate Thrust macros. -- #1105: Add a missing `` include. -- #1103: Fix regression of `thrust::detail::temporary_allocator` with non-CUDA - back ends. -- #1111: Use Thrust's random number engine instead of `std::`s in device code. -- #1108: Get rid of a GCC 9 warning about deprecated generation of copy ctors. - -# Thrust 1.9.8-1 (NVIDIA HPC SDK 20.3) - -## Summary - -Thrust 1.9.8-1 is a variant of 1.9.8 accompanying the NVIDIA HPC SDK 20.3 - release. -It contains modifications necessary to serve as the implementation of NVC++'s - GPU-accelerated C++17 Parallel Algorithms when using the CUDA Toolkit 11.0 - release. - -# Thrust 1.9.8 (CUDA Toolkit 11.0 Early Access) - -## Summary - -Thrust 1.9.8, which is included in the CUDA Toolkit 11.0 release, removes - Thrust's internal derivative of CUB, upstreams all relevant changes too CUB, - and adds CUB as a Git submodule. -It will now be necessary to do `git clone --recursive` when checking out - Thrust, and to update the CUB submodule when pulling in new Thrust changes. -Additionally, CUB is now included as a first class citizen in the CUDA toolkit. -Thrust 1.9.8 also fixes bugs preventing most Thrust algorithms from working - with more than `2^31-1` elements. -Now, `thrust::reduce`, `thrust::*_scan`, and related algorithms (aka most of - Thrust) work with large element counts. - -## Breaking Changes - -- Thrust will now use the version of CUB in your include path instead of its own - internal copy. - If you are using your own version of CUB, it may be older and incompatible - with Thrust. - It is recommended to simply delete your own version of CUB and use the - version of CUB that comes with Thrust. - -## Other Enhancements - -- Refactor Thrust and CUB to support 64-bit indices in most algorithms. - In most cases, Thrust now selects between kernels that use 32-bit indices and - 64-bit indices at runtime depending on the size of the input. - This means large element counts work, but small element counts do not have to - pay for the register usage of 64-bit indices if they are not needed. - Now, `thrust::reduce`, `thrust::*_scan`, and related algorithms (aka most of - Thrust) work with more than `2^31-1` elements. - Notably, `thrust::sort` is still limited to less than `2^31-1` elements. -- CUB is now a submodule and the internal copy of CUB has been removed. -- #1051: Stop specifying the `__launch_bounds__` minimum blocks parameter - because it messes up register allocation and increases register pressure, - and we don't actually know at compile time how many blocks we will use - (aside from single tile kernels). - -## Bug Fixes - -- #1020: After making a CUDA API call, always clear the global CUDA error state - by calling `cudaGetLastError`. -- #1021: Avoid calling destroy in the destructor of a Thrust vector if the - vector is empty. -- #1046: Actually throw `thrust::bad_alloc` when `thrust::system::cuda::malloc` - fails instead of just constructing a temporary and doing nothing with it. -- Add missing copy constructor or copy assignment operator to all classes that - GCC 9's `-Wdeprecated-copy` complains about -- Add missing move operations to `thrust::system::cuda::vector`. -- #1015: Check that the backend is CUDA before using CUDA-specifics in - `thrust::detail::temporary_allocator`. - Thanks to Hugh Winkler for this contribution. -- #1055: More correctly detect the presence of aligned/sized `new`/`delete`. -- #1043: Fix ill-formed specialization of `thrust::system::is_error_code_enum` - for `thrust::event_errc`. - Thanks to Toru Niina for this contribution. -- #1027: Add tests for `thrust::tuple_for_each` and `thrust::tuple_subset`. - Thanks to Ben Jude for this contribution. -- #1027: Use correct macro in `thrust::tuple_for_each`. - Thanks to Ben Jude for this contribution. -- #1026: Use correct MSVC version formatting in CMake. - Thanks to Ben Jude for this contribution. -- Workaround an NVCC issue with type aliases with template template arguments - containing a parameter pack. -- Remove unused functions from the CUDA backend which call slow CUDA attribute - query APIs. -- Replace `CUB_RUNTIME_FUNCTION` with `THRUST_RUNTIME_FUNCTION`. -- Correct typo in `thrust::transform` documentation. - Thanks to Eden Yefet for this contribution. - -## Known Issues - -- `thrust::sort` remains limited to `2^31-1` elements for now. - -# Thrust 1.9.7-1 (CUDA Toolkit 10.2 for Tegra) - -## Summary - -Thrust 1.9.7-1 is a minor release accompanying the CUDA Toolkit 10.2 release - for Tegra. -It is nearly identical to 1.9.7. - -## Bug Fixes - -- Remove support for GCC's broken nodiscard-like attribute. - -# Thrust 1.9.7 (CUDA Toolkit 10.2) - -## Summary - -Thrust 1.9.7 is a minor release accompanying the CUDA Toolkit 10.2 release. -Unfortunately, although the version and patch numbers are identical, one bug - fix present in Thrust 1.9.7 (NVBug 2646034: Fix incorrect dependency handling - for stream acquisition in `thrust::future`) was not included in the CUDA - Toolkit 10.2 preview release for AArch64 SBSA. -The tag `cuda-10.2aarch64sbsa` contains the exact version of Thrust present - in the CUDA Toolkit 10.2 preview release for AArch64 SBSA. - -## Bug Fixes - -- #967, NVBug 2448170: Fix the CUDA backend `thrust::for_each` so that it - supports large input sizes with 64-bit indices. -- NVBug 2646034: Fix incorrect dependency handling for stream acquisition in - `thrust::future`. - - Not present in the CUDA Toolkit 10.2 preview release for AArch64 SBSA. -- #968, NVBug 2612102: Fix the `thrust::mr::polymorphic_adaptor` to actually - use its template parameter. - -# Thrust 1.9.6-1 (NVIDIA HPC SDK 20.3) - -## Summary - -Thrust 1.9.6-1 is a variant of 1.9.6 accompanying the NVIDIA HPC SDK 20.3 - release. -It contains modifications necessary to serve as the implementation of NVC++'s - GPU-accelerated C++17 Parallel Algorithms when using the CUDA Toolkit 10.1 - Update 2 release. - -# Thrust 1.9.6 (CUDA Toolkit 10.1 Update 2) - -## Summary - -Thrust 1.9.6 is a minor release accompanying the CUDA Toolkit 10.1 Update 2 - release. - -## Bug Fixes - -- NVBug 2509847: Inconsistent alignment of `thrust::complex` -- NVBug 2586774: Compilation failure with Clang + older libstdc++ that doesn't - have `std::is_trivially_copyable` -- NVBug 200488234: CUDA header files contain Unicode characters which leads - compiling errors on Windows -- #949, #973, NVBug 2422333, NVBug 2522259, NVBug 2528822: - `thrust::detail::aligned_reinterpret_cast` must be annotated with - `__host__ __device__`. -- NVBug 2599629: Missing include in the OpenMP sort implementation -- NVBug 200513211: Truncation warning in test code under VC142 - -# Thrust 1.9.5 (CUDA Toolkit 10.1 Update 1) - -## Summary - -Thrust 1.9.5 is a minor release accompanying the CUDA Toolkit 10.1 Update 1 - release. - -## Bug Fixes - -- NVBug 2502854: Fixed assignment of - `thrust::device_vector>` between host and device. - -# Thrust 1.9.4 (CUDA Toolkit 10.1) - -## Summary - -Thrust 1.9.4 adds asynchronous interfaces for parallel algorithms, a new - allocator system including caching allocators and unified memory support, as - well as a variety of other enhancements, mostly related to - C++11/C++14/C++17/C++20 support. -The new asynchronous algorithms in the `thrust::async` namespace return - `thrust::event` or `thrust::future` objects, which can be waited upon to - synchronize with the completion of the parallel operation. - -## Breaking Changes - -Synchronous Thrust algorithms now block until all of their operations have - completed. -Use the new asynchronous Thrust algorithms for non-blocking behavior. - -## New Features - -- `thrust::event` and `thrust::future`, uniquely-owned asynchronous handles - consisting of a state (ready or not ready), content (some value; for - `thrust::future` only), and an optional set of objects that should be - destroyed only when the future's value is ready and has been consumed. - - The design is loosely based on C++11's `std::future`. - - They can be `.wait`'d on, and the value of a future can be waited on and - retrieved with `.get` or `.extract`. - - Multiple `thrust::event`s and `thrust::future`s can be combined with - `thrust::when_all`. - - `thrust::future`s can be converted to `thrust::event`s. - - Currently, these primitives are only implemented for the CUDA backend and - are C++11 only. -- New asynchronous algorithms that return `thrust::event`/`thrust::future`s, - implemented as C++20 range style customization points: - - `thrust::async::reduce`. - - `thrust::async::reduce_into`, which takes a target location to store the - reduction result into. - - `thrust::async::copy`, including a two-policy overload that allows - explicit cross system copies which execution policy properties can be - attached to. - - `thrust::async::transform`. - - `thrust::async::for_each`. - - `thrust::async::stable_sort`. - - `thrust::async::sort`. - - By default the asynchronous algorithms use the new caching allocators. - Deallocation of temporary storage is deferred until the destruction of - the returned `thrust::future`. The content of `thrust::future`s is - stored in either device or universal memory and transferred to the host - only upon request to prevent unnecessary data migration. - - Asynchronous algorithms are currently only implemented for the CUDA - system and are C++11 only. -- `exec.after(f, g, ...)`, a new execution policy method that takes a set of - `thrust::event`/`thrust::future`s and returns an execution policy that - operations on that execution policy should depend upon. -- New logic and mindset for the type requirements for cross-system sequence - copies (currently only used by `thrust::async::copy`), based on: - - `thrust::is_contiguous_iterator` and `THRUST_PROCLAIM_CONTIGUOUS_ITERATOR` - for detecting/indicating that an iterator points to contiguous storage. - - `thrust::is_trivially_relocatable` and - `THRUST_PROCLAIM_TRIVIALLY_RELOCATABLE` for detecting/indicating that a - type is `memcpy`able (based on principles from - [P1144](https://wg21.link/P1144)). - - The new approach reduces buffering, increases performance, and increases - correctness. - - The fast path is now enabled when copying CUDA `__half` and vector types with - `thrust::async::copy`. -- All Thrust synchronous algorithms for the CUDA backend now actually - synchronize. Previously, any algorithm that did not allocate temporary - storage (counterexample: `thrust::sort`) and did not have a - computation-dependent result (counterexample: `thrust::reduce`) would - actually be launched asynchronously. Additionally, synchronous algorithms - that allocated temporary storage would become asynchronous if a custom - allocator was supplied that did not synchronize on allocation/deallocation, - unlike `cudaMalloc`/`cudaFree`. So, now `thrust::for_each`, - `thrust::transform`, `thrust::sort`, etc are truly synchronous. In some - cases this may be a performance regression; if you need asynchrony, use the - new asynchronous algorithms. -- Thrust's allocator framework has been rewritten. It now uses a memory - resource system, similar to C++17's `std::pmr` but supporting static - polymorphism. Memory resources are objects that allocate untyped storage and - allocators are cheap handles to memory resources in this new model. The new - facilities live in ``. - - `thrust::mr::memory_resource`, the memory resource base class, - which takes a (possibly tagged) pointer to `void` type as a parameter. - - `thrust::mr::allocator`, an allocator backed by a memory - resource object. - - `thrust::mr::polymorphic_adaptor_resource`, a type-erased memory - resource adaptor. - - `thrust::mr::polymorphic_allocator`, a C++17-style polymorphic allocator - backed by a type-erased memory resource object. - - New tunable C++17-style caching memory resources, - `thrust::mr::(disjoint_)?(un)?synchronized_pool_resource`, designed to - cache both small object allocations and large repetitive temporary - allocations. The disjoint variants use separate storage for management of - the pool, which is necessary if the memory being allocated cannot be - accessed on the host (e.g. device memory). - - System-specific allocators were rewritten to use the new memory resource - framework. - - New `thrust::device_memory_resource` for allocating device memory. - - New `thrust::universal_memory_resource` for allocating memory that can be - accessed from both the host and device (e.g. `cudaMallocManaged`). - - New `thrust::universal_host_pinned_memory_resource` for allocating memory - that can be accessed from the host and the device but always resides in - host memory (e.g. `cudaMallocHost`). - - `thrust::get_per_device_resource` and `thrust::per_device_allocator`, which - lazily create and retrieve a per-device singleton memory resource. - - Rebinding mechanisms (`rebind_traits` and `rebind_alloc`) for - `thrust::allocator_traits`. - - `thrust::device_make_unique`, a factory function for creating a - `std::unique_ptr` to a newly allocated object in device memory. - - ``, a C++11 implementation of the C++17 - uninitialized memory algorithms. - - `thrust::allocate_unique` and friends, based on the proposed C++23 - [`std::allocate_unique`](https://wg21.link/P0211). -- New type traits and metaprogramming facilities. Type traits are slowly being - migrated out of `thrust::detail::` and ``; their new home - will be `thrust::` and ``. - - `thrust::is_execution_policy`. - - `thrust::is_operator_less_or_greater_function_object`, which detects - `thrust::less`, `thrust::greater`, `std::less`, and `std::greater`. - - `thrust::is_operator_plus_function_object``, which detects `thrust::plus` - and `std::plus`. - - `thrust::remove_cvref(_t)?`, a C++11 implementation of C++20's - `thrust::remove_cvref(_t)?`. - - `thrust::void_t`, and various other new type traits. - - `thrust::integer_sequence` and friends, a C++11 implementation of C++20's - `std::integer_sequence` - - `thrust::conjunction`, `thrust::disjunction`, and `thrust::disjunction`, a - C++11 implementation of C++17's logical metafunctions. - - Some Thrust type traits (such as `thrust::is_constructible`) have been - redefined in terms of C++11's type traits when they are available. -- ``, new `std::tuple` algorithms: - - `thrust::tuple_transform`. - - `thrust::tuple_for_each`. - - `thrust::tuple_subset`. -- Miscellaneous new `std::`-like facilities: - - `thrust::optional`, a C++11 implementation of C++17's `std::optional`. - - `thrust::addressof`, an implementation of C++11's `std::addressof`. - - `thrust::next` and `thrust::prev`, an implementation of C++11's `std::next` - and `std::prev`. - - `thrust::square`, a `` style unary function object that - multiplies its argument by itself. - - `` and `thrust::numeric_limits`, a customized version of - `` and `std::numeric_limits`. -- ``, new general purpose preprocessor facilities: - - `THRUST_PP_CAT[2-5]`, concatenates two to five tokens. - - `THRUST_PP_EXPAND(_ARGS)?`, performs double expansion. - - `THRUST_PP_ARITY` and `THRUST_PP_DISPATCH`, tools for macro overloading. - - `THRUST_PP_BOOL`, boolean conversion. - - `THRUST_PP_INC` and `THRUST_PP_DEC`, increment/decrement. - - `THRUST_PP_HEAD`, a variadic macro that expands to the first argument. - - `THRUST_PP_TAIL`, a variadic macro that expands to all its arguments after - the first. - - `THRUST_PP_IIF`, bitwise conditional. - - `THRUST_PP_COMMA_IF`, and `THRUST_PP_HAS_COMMA`, facilities for adding and - detecting comma tokens. - - `THRUST_PP_IS_VARIADIC_NULLARY`, returns true if called with a nullary - `__VA_ARGS__`. - - `THRUST_CURRENT_FUNCTION`, expands to the name of the current function. -- New C++11 compatibility macros: - - `THRUST_NODISCARD`, expands to `[[nodiscard]]` when available and the best - equivalent otherwise. - - `THRUST_CONSTEXPR`, expands to `constexpr` when available and the best - equivalent otherwise. - - `THRUST_OVERRIDE`, expands to `override` when available and the best - equivalent otherwise. - - `THRUST_DEFAULT`, expands to `= default;` when available and the best - equivalent otherwise. - - `THRUST_NOEXCEPT`, expands to `noexcept` when available and the best - equivalent otherwise. - - `THRUST_FINAL`, expands to `final` when available and the best equivalent - otherwise. - - `THRUST_INLINE_CONSTANT`, expands to `inline constexpr` when available and - the best equivalent otherwise. -- ``, new C++11-only type deduction helpers: - - `THRUST_DECLTYPE_RETURNS*`, expand to function definitions with suitable - conditional `noexcept` qualifiers and trailing return types. - - `THRUST_FWD(x)`, expands to `::std::forward(x)`. - - `THRUST_MVCAP`, expands to a lambda move capture. - - `THRUST_RETOF`, expands to a decltype computing the return type of an - invocable. -- New CMake build system. - -## New Examples - -- `mr_basic` demonstrates how to use the new memory resource allocator system. - -## Other Enhancements - -- Tagged pointer enhancements: - - New `thrust::pointer_traits` specialization for `void const*`. - - `nullptr` support to Thrust tagged pointers. - - New `explicit operator bool` for Thrust tagged pointers when using C++11 - for `std::unique_ptr` interoperability. - - Added `thrust::reinterpret_pointer_cast` and `thrust::static_pointer_cast` - for casting Thrust tagged pointers. -- Iterator enhancements: - - `thrust::iterator_system` is now SFINAE friendly. - - Removed cv qualifiers from iterator types when using - `thrust::iterator_system`. -- Static assert enhancements: - - New `THRUST_STATIC_ASSERT_MSG`, takes an optional string constant to be - used as the error message when possible. - - Update `THRUST_STATIC_ASSERT(_MSG)` to use C++11's `static_assert` when - it's available. - - Introduce a way to test for static assertions. -- Testing enhancements: - - Additional scalar and sequence types, including non-builtin types and - vectors with unified memory allocators, have been added to the list of - types used by generic unit tests. - - The generation of random input data has been improved to increase the range - of values used and catch more corner cases. - - New `unittest::truncate_to_max_representable` utility for avoiding the - generation of ranges that cannot be represented by the underlying element - type in generic unit test code. - - The test driver now synchronizes with CUDA devices and check for errors - after each test, when switching devices, and after each raw kernel launch. - - The `warningtester` uber header is now compiled with NVCC to avoid needing - to disable CUDA-specific code with the preprocessor. - - Fixed the unit test framework's `ASSERT_*` to print `char`s as `int`s. - - New `DECLARE_INTEGRAL_VARIABLE_UNITTEST` test declaration macro. - - New `DECLARE_VARIABLE_UNITTEST_WITH_TYPES_AND_NAME` test declaration macro. - - `thrust::system_error` in the CUDA backend now print out its `cudaError_t` - enumerator in addition to the diagnostic message. - - Stopped using conditionally signed types like `char`. - -## Bug Fixes - -- #897, NVBug 2062242: Fix compilation error when using `__device__` lambdas - with `thrust::reduce` on MSVC. -- #908, NVBug 2089386: Static assert that `thrust::generate`/`thrust::fill` - isn't operating on const iterators. -- #919 Fix compilation failure with `thrust::zip_iterator` and - `thrust::complex`. -- #924, NVBug 2096679, NVBug 2315990: Fix dispatch for the CUDA backend's - `thrust::reduce` to use two functions (one with the pragma for disabling - exec checks, one with `THRUST_RUNTIME_FUNCTION`) instead of one. This fixes - a regression with device compilation that started in CUDA Toolkit 9.2. -- #928, NVBug 2341455: Add missing `__host__ __device__` annotations to a - `thrust::complex::operator=` to satisfy GoUDA. -- NVBug 2094642: Make `thrust::vector_base::clear` not depend on the element - type being default constructible. -- NVBug 2289115: Remove flaky `simple_cuda_streams` example. -- NVBug 2328572: Add missing `thrust::device_vector` constructor that takes an - allocator parameter. -- NVBug 2455740: Update the `range_view` example to not use device-side launch. -- NVBug 2455943: Ensure that sized unit tests that use - `thrust::counting_iterator` perform proper truncation. -- NVBug 2455952: Refactor questionable `thrust::copy_if` unit tests. - -# Thrust 1.9.3 (CUDA Toolkit 10.0) - -## Summary - -Thrust 1.9.3 unifies and integrates CUDA Thrust and GitHub Thrust. - -## Bug Fixes - -- #725, #850, #855, #859, #860: Unify the `thrust::iter_swap` interface and fix - `thrust::device_reference` swapping. -- NVBug 2004663: Add a `data` method to `thrust::detail::temporary_array` and - refactor temporary memory allocation in the CUDA backend to be exception - and leak safe. -- #886, #894, #914: Various documentation typo fixes. -- #724: Provide `NVVMIR_LIBRARY_DIR` environment variable to NVCC. -- #878: Optimize `thrust::min/max_element` to only use - `thrust::detail::get_iterator_value` for non-numeric types. -- #899: Make `thrust::cuda::experimental::pinned_allocator`'s comparison - operators `const`. -- NVBug 2092152: Remove all includes of ``. -- #911: Fix default comparator element type for `thrust::merge_by_key`. - -## Acknowledgments - -- Thanks to Andrew Corrigan for contributing fixes for swapping interfaces. -- Thanks to Francisco Facioni for contributing optimizations for - `thrust::min/max_element`. - -# Thrust 1.9.2 (CUDA Toolkit 9.2) - -## Summary - -Thrust 1.9.2 brings a variety of performance enhancements, bug fixes and test - improvements. -CUB 1.7.5 was integrated, enhancing the performance of `thrust::sort` on - small data types and `thrust::reduce`. -Changes were applied to `complex` to optimize memory access. -Thrust now compiles with compiler warnings enabled and treated as errors. -Additionally, the unit test suite and framework was enhanced to increase - coverage. - -## Breaking Changes - -- The `fallback_allocator` example was removed, as it was buggy and difficult - to support. - -## New Features - -- ``, utilities for memory alignment: - - `thrust::aligned_reinterpret_cast`. - - `thrust::aligned_storage_size`, which computes the amount of storage needed - for an object of a particular size and alignment. - - `thrust::alignment_of`, a C++03 implementation of C++11's - `std::alignment_of`. - - `thrust::aligned_storage`, a C++03 implementation of C++11's - `std::aligned_storage`. - - `thrust::max_align_t`, a C++03 implementation of C++11's - `std::max_align_t`. - -## Bug Fixes - -- NVBug 200385527, NVBug 200385119, NVBug 200385113, NVBug 200349350, NVBug - 2058778: Various compiler warning issues. -- NVBug 200355591: `thrust::reduce` performance issues. -- NVBug 2053727: Fixed an ADL bug that caused user-supplied `allocate` to be - overlooked but `deallocate` to be called with GCC <= 4.3. -- NVBug 1777043: Fixed `thrust::complex` to work with `thrust::sequence`. - -# Thrust 1.9.1-2 (CUDA Toolkit 9.1) - -## Summary - -Thrust 1.9.1-2 integrates version 1.7.4 of CUB and introduces a new CUDA backend - for `thrust::reduce` based on CUB. - -## Bug Fixes - -- NVBug 1965743: Remove unnecessary static qualifiers. -- NVBug 1940974: Fix regression causing a compilation error when using - `thrust::merge_by_key` with `thrust::constant_iterator`s. -- NVBug 1904217: Allow callables that take non-const refs to be used with - `thrust::reduce` and `thrust::*_scan`. - -# Thrust 1.9.0-5 (CUDA Toolkit 9.0) - -## Summary - -Thrust 1.9.0-5 replaces the original CUDA backend (bulk) with a new one - written using CUB, a high performance CUDA collectives library. -This brings a substantial performance improvement to the CUDA backend across - the board. - -## Breaking Changes - -- Any code depending on CUDA backend implementation details will likely be - broken. - -## New Features - -- New CUDA backend based on CUB which delivers substantially higher performance. -- `thrust::transform_output_iterator`, a fancy iterator that applies a function - to the output before storing the result. - -## New Examples - -- `transform_output_iterator` demonstrates use of the new fancy iterator - `thrust::transform_output_iterator`. - -## Other Enhancements - -- When C++11 is enabled, functors do not have to inherit from - `thrust::(unary|binary)_function` anymore to be used with - `thrust::transform_iterator`. -- Added C++11 only move constructors and move assignment operators for - `thrust::detail::vector_base`-based classes, e.g. `thrust::host_vector`, - `thrust::device_vector`, and friends. - -## Bug Fixes - -- `sin(thrust::complex)` no longer has precision loss to float. - -## Acknowledgments - -- Thanks to Manuel Schiller for contributing a C++11 based enhancement - regarding the deduction of functor return types, improving the performance - of `thrust::unique` and implementing `thrust::transform_output_iterator`. -- Thanks to Thibault Notargiacomo for the implementation of move semantics for - the `thrust::vector_base`-based classes. -- Thanks to Duane Merrill for developing CUB and helping to integrate it into - Thrust's backend. - -# Thrust 1.8.3 (CUDA Toolkit 8.0) - -## Summary - -Thrust 1.8.3 is a small bug fix release. - -## New Examples - -- `range_view` demonstrates the use of a view (a non-owning wrapper for an - iterator range with a container-like interface). - -## Bug Fixes - -- `thrust::(min|max|minmax)_element` can now accept raw device pointers when - an explicit device execution policy is used. -- `thrust::clear` operations on vector types no longer requires the element - type to have a default constructor. - -# Thrust 1.8.2 (CUDA Toolkit 7.5) - -## Summary - -Thrust 1.8.2 is a small bug fix release. - -## Bug Fixes - -- Avoid warnings and errors concerning user functions called from - `__host__ __device__` functions. -- #632: Fix an error in `thrust::set_intersection_by_key` with the CUDA backend. -- #651: `thrust::copy` between host and device now accepts execution policies - with streams attached, i.e. `thrust::::cuda::par.on(stream)`. -- #664: `thrust::for_each` and algorithms based on it no longer ignore streams - attached to execution policys. - -## Known Issues - -- #628: `thrust::reduce_by_key` for the CUDA backend fails for Compute - Capability 5.0 devices. - -# Thrust 1.8.1 (CUDA Toolkit 7.0) - -## Summary - -Thrust 1.8.1 is a small bug fix release. - -## Bug Fixes - -- #615, #620: Fixed `thrust::for_each` and `thrust::reduce` to no longer fail on - large inputs. - -## Known Issues - -- #628: `thrust::reduce_by_key` for the CUDA backend fails for Compute - Capability 5.0 devices. - -# Thrust 1.8.0 - -## Summary - -Thrust 1.8.0 introduces support for algorithm invocation from CUDA device - code, support for CUDA streams, and algorithm performance improvements. -Users may now invoke Thrust algorithms from CUDA device code, providing a - parallel algorithms library to CUDA programmers authoring custom kernels, as - well as allowing Thrust programmers to nest their algorithm calls within - functors. -The `thrust::seq` execution policy allows users to require sequential algorithm - execution in the calling thread and makes a sequential algorithms library - available to individual CUDA threads. -The `.on(stream)` syntax allows users to request a CUDA stream for kernels - launched during algorithm execution. -Finally, new CUDA algorithm implementations provide substantial performance - improvements. - -## New Features - -- Algorithms in CUDA Device Code: - - Thrust algorithms may now be invoked from CUDA `__device__` and - `__host__` __device__ functions. - Algorithms invoked in this manner must be invoked with an execution - policy as the first parameter. - The following execution policies are supported in CUDA __device__ code: - - `thrust::seq` - - `thrust::cuda::par` - - `thrust::device`, when THRUST_DEVICE_SYSTEM == THRUST_DEVICE_SYSTEM_CUDA. - - Device-side algorithm execution may not be parallelized unless CUDA Dynamic - Parallelism is available. -- Execution Policies: - - CUDA Streams - - The `thrust::cuda::par.on(stream)` syntax allows users to request that - CUDA kernels launched during algorithm execution should occur on a given - stream. - - Algorithms executed with a CUDA stream in this manner may still - synchronize with other streams when allocating temporary storage or - returning results to the CPU. - - `thrust::seq`, which allows users to require that an algorithm execute - sequentially in the calling thread. -- `thrust::complex`, a complex number data type. - -## New Examples - -- simple_cuda_streams demonstrates how to request a CUDA stream during - algorithm execution. -- async_reduce demonstrates ways to achieve algorithm invocations which are - asynchronous with the calling thread. - -## Other Enhancements - -- CUDA sort performance for user-defined types is 300% faster on Tesla K20c for - large problem sizes. -- CUDA merge performance is 200% faster on Tesla K20c for large problem sizes. -- CUDA sort performance for primitive types is 50% faster on Tesla K20c for - large problem sizes. -- CUDA reduce_by_key performance is 25% faster on Tesla K20c for large problem - sizes. -- CUDA scan performance is 15% faster on Tesla K20c for large problem sizes. -- fallback_allocator example is simpler. - -## Bug Fixes - -- #364: Iterators with unrelated system tags may be used with algorithms invoked - with an execution policy -- #371: Do not redefine `__CUDA_ARCH__`. -- #379: Fix crash when dereferencing transform_iterator on the host. -- #391: Avoid use of uppercase variable names. -- #392: Fix `thrust::copy` between `cusp::complex` and `std::complex`. -- #396: Program compiled with gcc < 4.3 hangs during comparison sort. -- #406: `fallback_allocator.cu` example checks device for unified addressing support. -- #417: Avoid using `std::less` in binary search algorithms. -- #418: Avoid various warnings. -- #443: Including version.h no longer configures default systems. -- #578: NVCC produces warnings when sequential algorithms are used with CPU systems. - -## Known Issues - -- When invoked with primitive data types, thrust::sort, thrust::sort_by_key, - thrust::stable_sort, & thrust::stable_sort_by_key may -- Sometimes linking fails when compiling with `-rdc=true` with NVCC. -- The CUDA implementation of thrust::reduce_by_key incorrectly outputs the last - element in a segment of equivalent keys instead of the first. - -## Acknowledgments - -- Thanks to Sean Baxter for contributing faster CUDA reduce, merge, and scan - implementations. -- Thanks to Duane Merrill for contributing a faster CUDA radix sort implementation. -- Thanks to Filipe Maia for contributing the implementation of thrust::complex. - -# Thrust 1.7.2 (CUDA Toolkit 6.5) - -## Summary - -Thrust 1.7.2 is a minor bug fix release. - -## Bug Fixes - -- Avoid use of `std::min` in generic find implementation. - -# Thrust 1.7.1 (CUDA Toolkit 6.0) - -## Summary - -Thrust 1.7.1 is a minor bug fix release. - -## Bug Fixes - -- Eliminate identifiers in `set_operations.cu` example with leading underscore. -- Eliminate unused variable warning in CUDA `reduce_by_key` implementation. -- Avoid deriving function objects from `std::unary_function` and - `std::binary_function`. - -# Thrust 1.7.0 (CUDA Toolkit 5.5) - -## Summary - -Thrust 1.7.0 introduces a new interface for controlling algorithm execution as - well as several new algorithms and performance improvements. -With this new interface, users may directly control how algorithms execute as - well as details such as the allocation of temporary storage. -Key/value versions of thrust::merge and the set operation algorithms have been - added, as well stencil versions of partitioning algorithms. -thrust::tabulate has been introduced to tabulate the values of functions taking - integers. -For 32b types, new CUDA merge and set operations provide 2-15x faster - performance while a new CUDA comparison sort provides 1.3-4x faster - performance. -Finally, a new TBB reduce_by_key implementation provides 80% faster - performance. - -## Breaking Changes - -- Dispatch: - - Custom user backend systems' tag types must now inherit from the - corresponding system's execution_policy template (e.g. - thrust::cuda::execution_policy) instead of the tag struct (e.g. - thrust::cuda::tag). Otherwise, algorithm specializations will silently go - unfound during dispatch. See examples/minimal_custom_backend.cu and - examples/cuda/fallback_allocator.cu for usage examples. - - thrust::advance and thrust::distance are no longer dispatched based on - iterator system type and thus may no longer be customized. -- Iterators: - - iterator_facade and iterator_adaptor's Pointer template parameters have - been eliminated. - - iterator_adaptor has been moved into the thrust namespace (previously - thrust::experimental::iterator_adaptor). - - iterator_facade has been moved into the thrust namespace (previously - thrust::experimental::iterator_facade). - - iterator_core_access has been moved into the thrust namespace (previously - thrust::experimental::iterator_core_access). - - All iterators' nested pointer typedef (the type of the result of - operator->) is now void instead of a pointer type to indicate that such - expressions are currently impossible. - - Floating point counting_iterators' nested difference_type typedef is now a - signed integral type instead of a floating point type. -- Other: - - normal_distribution has been moved into the thrust::random namespace - (previously thrust::random::experimental::normal_distribution). - - Placeholder expressions may no longer include the comma operator. - -## New Features -- Execution Policies: - - Users may directly control the dispatch of algorithm invocations with - optional execution policy arguments. - For example, instead of wrapping raw pointers allocated by cudaMalloc with - thrust::device_ptr, the thrust::device execution_policy may be passed as - an argument to an algorithm invocation to enable CUDA execution. - - The following execution policies are supported in this version: - - `thrust::host` - - `thrust::device` - - `thrust::cpp::par` - - `thrust::cuda::par` - - `thrust::omp::par` - - `thrust::tbb::par` -- Algorithms: - - `thrust::merge_by_key` - - `thrust::partition` with stencil - - `thrust::partition_copy` with stencil - - `thrust::set_difference_by_key` - - `thrust::set_intersection_by_key` - - `thrust::set_symmetric_difference_by_key` - - `thrust::set_union_by_key` - - `thrust::stable_partition with stencil` - - `thrust::stable_partition_copy with stencil` - - `thrust::tabulate` -- Memory Allocation: - - `thrust::malloc` - - `thrust::free` - - `thrust::get_temporary_buffer` - - `thrust::return_temporary_buffer` - -## New Examples - -- uninitialized_vector demonstrates how to use a custom allocator to avoid the - automatic initialization of elements in thrust::device_vector. - -## Other Enhancements - -- Authors of custom backend systems may manipulate arbitrary state during - algorithm dispatch by incorporating it into their execution_policy parameter. -- Users may control the allocation of temporary storage during algorithm - execution by passing standard allocators as parameters via execution policies - such as thrust::device. -- THRUST_DEVICE_SYSTEM_CPP has been added as a compile-time target for the - device backend. -- CUDA merge performance is 2-15x faster. -- CUDA comparison sort performance is 1.3-4x faster. -- CUDA set operation performance is 1.5-15x faster. -- TBB reduce_by_key performance is 80% faster. -- Several algorithms have been parallelized with TBB. -- Support for user allocators in vectors has been improved. -- The sparse_vector example is now implemented with merge_by_key instead of - sort_by_key. -- Warnings have been eliminated in various contexts. -- Warnings about __host__ or __device__-only functions called from __host__ - __device__ functions have been eliminated in various contexts. -- Documentation about algorithm requirements have been improved. -- Simplified the minimal_custom_backend example. -- Simplified the cuda/custom_temporary_allocation example. -- Simplified the cuda/fallback_allocator example. - -## Bug Fixes - -- #248: Fix broken `thrust::counting_iterator` behavior with OpenMP. -- #231, #209: Fix set operation failures with CUDA. -- #187: Fix incorrect occupancy calculation with CUDA. -- #153: Fix broken multi GPU behavior with CUDA. -- #142: Eliminate warning produced by `thrust::random::taus88` and MSVC 2010. -- #208: Correctly initialize elements in temporary storage when necessary. -- #16: Fix compilation error when sorting bool with CUDA. -- #10: Fix ambiguous overloads of `thrust::reinterpret_tag`. - -## Known Issues - -- GCC 4.3 and lower may fail to dispatch thrust::get_temporary_buffer correctly - causing infinite recursion in examples such as - cuda/custom_temporary_allocation. - -## Acknowledgments - -- Thanks to Sean Baxter, Bryan Catanzaro, and Manjunath Kudlur for contributing - a faster merge implementation for CUDA. -- Thanks to Sean Baxter for contributing a faster set operation implementation - for CUDA. -- Thanks to Cliff Woolley for contributing a correct occupancy calculation - algorithm. - -# Thrust 1.6.0 - -## Summary - -Thrust 1.6.0 provides an interface for customization and extension and a new - backend system based on the Threading Building Blocks library. -With this new interface, programmers may customize the behavior of specific - algorithms as well as control the allocation of temporary storage or invent - entirely new backends. -These enhancements also allow multiple different backend systems - such as CUDA and OpenMP to coexist within a single program. -Support for TBB allows Thrust programs to integrate more naturally into - applications which may already employ the TBB task scheduler. - -## Breaking Changes - -- The header has been moved to - -- thrust::experimental::cuda::pinned_allocator has been moved to - thrust::cuda::experimental::pinned_allocator -- The macro THRUST_DEVICE_BACKEND has been renamed THRUST_DEVICE_SYSTEM -- The macro THRUST_DEVICE_BACKEND_CUDA has been renamed THRUST_DEVICE_SYSTEM_CUDA -- The macro THRUST_DEVICE_BACKEND_OMP has been renamed THRUST_DEVICE_SYSTEM_OMP -- thrust::host_space_tag has been renamed thrust::host_system_tag -- thrust::device_space_tag has been renamed thrust::device_system_tag -- thrust::any_space_tag has been renamed thrust::any_system_tag -- thrust::iterator_space has been renamed thrust::iterator_system - -## New Features - -- Backend Systems - - Threading Building Blocks (TBB) is now supported -- Algorithms - - `thrust::for_each_n` - - `thrust::raw_reference_cast` -- Types - - `thrust::pointer` - - `thrust::reference` - -## New Examples - -- `cuda/custom_temporary_allocation` -- `cuda/fallback_allocator` -- `device_ptr` -- `expand` -- `minimal_custom_backend` -- `raw_reference_cast` -- `set_operations` - -## Other Enhancements - -- `thrust::for_each` now returns the end of the input range similar to most - other algorithms. -- `thrust::pair` and `thrust::tuple` have swap functionality. -- All CUDA algorithms now support large data types. -- Iterators may be dereferenced in user `__device__` or `__global__` functions. -- The safe use of different backend systems is now possible within a single - binary - -## Bug Fixes - -- #469 `min_element` and `max_element` algorithms no longer require a const comparison operator - -## Known Issues - -- NVCC may crash when parsing TBB headers on Windows. - -# Thrust 1.5.3 (CUDA Toolkit 5.0) - -## Summary - -Thrust 1.5.3 is a minor bug fix release. - -## Bug Fixes - -- Avoid warnings about potential race due to `__shared__` non-POD variable - -# Thrust 1.5.2 (CUDA Toolkit 4.2) - -## Summary - -Thrust 1.5.2 is a minor bug fix release. - -## Bug Fixes - -- Fixed warning about C-style initialization of structures - -# Thrust 1.5.1 (CUDA Toolkit 4.1) - -## Summary - -Thrust 1.5.1 is a minor bug fix release. - -## Bug Fixes - -- Sorting data referenced by permutation_iterators on CUDA produces invalid results - -# Thrust 1.5.0 - -## Summary - -Thrust 1.5.0 provides introduces new programmer productivity and performance - enhancements. -New functionality for creating anonymous "lambda" functions has been added. -A faster host sort provides 2-10x faster performance for sorting arithmetic - types on (single-threaded) CPUs. -A new OpenMP sort provides 2.5x-3.0x speedup over the host sort using a - quad-core CPU. -When sorting arithmetic types with the OpenMP backend the combined performance - improvement is 5.9x for 32-bit integers and ranges from 3.0x (64-bit types) to - 14.2x (8-bit types). -A new CUDA `reduce_by_key` implementation provides 2-3x faster - performance. - -## Breaking Changes -- device_ptr no longer unsafely converts to device_ptr without an - explicit cast. - Use the expression device_pointer_cast(static_cast(void_ptr.get())) to - convert, for example, device_ptr to device_ptr. - -## New Features - -- Algorithms: - - Stencil-less `thrust::transform_if`. -- Lambda placeholders - -## New Examples -- lambda - -## Other Enhancements - -- Host sort is 2-10x faster for arithmetic types -- OMP sort provides speedup over host sort -- `reduce_by_key` is 2-3x faster -- `reduce_by_key` no longer requires O(N) temporary storage -- CUDA scan algorithms are 10-40% faster -- `host_vector` and `device_vector` are now documented -- out-of-memory exceptions now provide detailed information from CUDART -- improved histogram example -- `device_reference` now has a specialized swap -- `reduce_by_key` and scan algorithms are compatible with `discard_iterator` - -## Bug Fixes - -- #44: Allow `thrust::host_vector` to compile when `value_type` uses - `__align__`. -- #198: Allow `thrust::adjacent_difference` to permit safe in-situ operation. -- #303: Make thrust thread-safe. -- #313: Avoid race conditions in `thrust::device_vector::insert`. -- #314: Avoid unintended ADL invocation when dispatching copy. -- #365: Fix merge and set operation failures. - -## Known Issues - -- None - -## Acknowledgments - -- Thanks to Manjunath Kudlur for contributing his Carbon library, from which - the lambda functionality is derived. -- Thanks to Jean-Francois Bastien for suggesting a fix for #303. - -# Thrust 1.4.0 (CUDA Toolkit 4.0) - -## Summary - -Thrust 1.4.0 is the first release of Thrust to be included in the CUDA Toolkit. -Additionally, it brings many feature and performance improvements. -New set theoretic algorithms operating on sorted sequences have been added. -Additionally, a new fancy iterator allows discarding redundant or otherwise - unnecessary output from algorithms, conserving memory storage and bandwidth. - -## Breaking Changes - -- Eliminations - - `thrust/is_sorted.h` - - `thrust/utility.h` - - `thrust/set_intersection.h` - - `thrust/experimental/cuda/ogl_interop_allocator.h` and the functionality - therein - - `thrust::deprecated::copy_when` - - `thrust::deprecated::absolute_value` - - `thrust::deprecated::copy_when` - - `thrust::deprecated::absolute_value` - - `thrust::deprecated::copy_when` - - `thrust::deprecated::absolute_value` - - `thrust::gather` and `thrust::scatter` from host to device and vice versa - are no longer supported. - - Operations which modify the elements of a thrust::device_vector are no longer - available from source code compiled without nvcc when the device backend - is CUDA. - Instead, use the idiom from the cpp_interop example. - -## New Features - -- Algorithms: - - `thrust::copy_n` - - `thrust::merge` - - `thrust::set_difference` - - `thrust::set_symmetric_difference` - - `thrust::set_union` - -- Types - - `thrust::discard_iterator` - -- Device Support: - - Compute Capability 2.1 GPUs. - -## New Examples - -- run_length_decoding - -## Other Enhancements - -- Compilation warnings are substantially reduced in various contexts. -- The compilation time of thrust::sort, thrust::stable_sort, - thrust::sort_by_key, and thrust::stable_sort_by_key are substantially - reduced. -- A fast sort implementation is used when sorting primitive types with - thrust::greater. -- The performance of thrust::set_intersection is improved. -- The performance of thrust::fill is improved on SM 1.x devices. -- A code example is now provided in each algorithm's documentation. -- thrust::reverse now operates in-place - -## Bug Fixes - -- #212: `thrust::set_intersection` works correctly for large input sizes. -- #275: `thrust::counting_iterator` and `thrust::constant_iterator` work - correctly with OpenMP as the backend when compiling with optimization. -- #256: `min` and `max` correctly return their first argument as a tie-breaker -- #248: `NDEBUG` is interpreted incorrectly - -## Known Issues - -- NVCC may generate code containing warnings when compiling some Thrust - algorithms. -- When compiling with `-arch=sm_1x`, some Thrust algorithms may cause NVCC to - issue benign pointer advisories. -- When compiling with `-arch=sm_1x` and -G, some Thrust algorithms may fail to - execute correctly. -- `thrust::inclusive_scan`, `thrust::exclusive_scan`, - `thrust::inclusive_scan_by_key`, and `thrust::exclusive_scan_by_key` are - currently incompatible with `thrust::discard_iterator`. - -## Acknowledgments - -- Thanks to David Tarjan for improving the performance of set_intersection. -- Thanks to Duane Merrill for continued help with sort. -- Thanks to Nathan Whitehead for help with CUDA Toolkit integration. - -# Thrust 1.3.0 - -## Summary - -Thrust 1.3.0 provides support for CUDA Toolkit 3.2 in addition to many feature - and performance enhancements. -Performance of the sort and sort_by_key algorithms is improved by as much as 3x - in certain situations. -The performance of stream compaction algorithms, such as copy_if, is improved - by as much as 2x. -CUDA errors are now converted to runtime exceptions using the system_error - interface. -Combined with a debug mode, also new in 1.3, runtime errors can be located with - greater precision. -Lastly, a few header files have been consolidated or renamed for clarity. -See the deprecations section below for additional details. - -## Breaking Changes - -- Promotions - - thrust::experimental::inclusive_segmented_scan has been renamed - thrust::inclusive_scan_by_key and exposes a different interface - - thrust::experimental::exclusive_segmented_scan has been renamed - thrust::exclusive_scan_by_key and exposes a different interface - - thrust::experimental::partition_copy has been renamed - thrust::partition_copy and exposes a different interface - - thrust::next::gather has been renamed thrust::gather - - thrust::next::gather_if has been renamed thrust::gather_if - - thrust::unique_copy_by_key has been renamed thrust::unique_by_key_copy -- Deprecations - - thrust::copy_when has been renamed thrust::deprecated::copy_when - - thrust::absolute_value has been renamed thrust::deprecated::absolute_value - - The header thrust/set_intersection.h is now deprecated; use - thrust/set_operations.h instead - - The header thrust/utility.h is now deprecated; use thrust/swap.h instead - - The header thrust/swap_ranges.h is now deprecated; use thrust/swap.h instead -- Eliminations - - thrust::deprecated::gather - - thrust::deprecated::gather_if - - thrust/experimental/arch.h and the functions therein - - thrust/sorting/merge_sort.h - - thrust/sorting/radix_sort.h -- NVCC 2.3 is no longer supported - -## New Features - -- Algorithms: - - `thrust::exclusive_scan_by_key` - - `thrust::find` - - `thrust::find_if` - - `thrust::find_if_not` - - `thrust::inclusive_scan_by_key` - - `thrust::is_partitioned` - - `thrust::is_sorted_until` - - `thrust::mismatch` - - `thrust::partition_point` - - `thrust::reverse` - - `thrust::reverse_copy` - - `thrust::stable_partition_copy` - -- Types: - - `thrust::system_error` and related types. - - `thrust::experimental::cuda::ogl_interop_allocator`. - - `thrust::bit_and`, `thrust::bit_or`, and `thrust::bit_xor`. - -- Device Support: - - GF104-based GPUs. - -## New Examples - -- opengl_interop.cu -- repeated_range.cu -- simple_moving_average.cu -- sparse_vector.cu -- strided_range.cu - -## Other Enhancements - -- Performance of thrust::sort and thrust::sort_by_key is substantially improved - for primitive key types -- Performance of thrust::copy_if is substantially improved -- Performance of thrust::reduce and related reductions is improved -- THRUST_DEBUG mode added -- Callers of Thrust functions may detect error conditions by catching - thrust::system_error, which derives from std::runtime_error -- The number of compiler warnings generated by Thrust has been substantially - reduced -- Comparison sort now works correctly for input sizes > 32M -- min & max usage no longer collides with definitions -- Compiling against the OpenMP backend no longer requires nvcc -- Performance of device_vector initialized in .cpp files is substantially - improved in common cases -- Performance of thrust::sort_by_key on the host is substantially improved - -## Bug Fixes - -- Debug device code now compiles correctly -- thrust::uninitialized_copy and thrust::uninitialized_fill now dispatch - constructors on the device rather than the host - -## Known Issues - -- #212 set_intersection is known to fail for large input sizes -- partition_point is known to fail for 64b types with nvcc 3.2 - -Acknowledgments -- Thanks to Duane Merrill for contributing a fast CUDA radix sort implementation -- Thanks to Erich Elsen for contributing an implementation of find_if -- Thanks to Andrew Corrigan for contributing changes which allow the OpenMP - backend to compile in the absence of nvcc -- Thanks to Andrew Corrigan, Cliff Wooley, David Coeurjolly, Janick Martinez - Esturo, John Bowers, Maxim Naumov, Michael Garland, and Ryuta Suzuki for - bug reports -- Thanks to Cliff Woolley for help with testing - -# Thrust 1.2.1 - -## Summary - -Small fixes for compatibility for the CUDA Toolkit 3.1. - -## Known Issues - -- `thrust::inclusive_scan` and `thrust::exclusive_scan` may fail with very - large types. -- MSVC may fail to compile code using both sort and binary search algorithms. -- `thrust::uninitialized_fill` and `thrust::uninitialized_copy` dispatch - constructors on the host rather than the device. -- #109: Some algorithms may exhibit poor performance with the OpenMP backend - with large numbers (>= 6) of CPU threads. -- `thrust::default_random_engine::discard` is not accelerated with NVCC 2.3 -- NVCC 3.1 may fail to compile code using types derived from - `thrust::subtract_with_carry_engine`, such as `thrust::ranlux24` and - `thrust::ranlux48`. - -# Thrust 1.2.0 - -## Summary - -Thrust 1.2 introduces support for compilation to multicore CPUs and the Ocelot - virtual machine, and several new facilities for pseudo-random number - generation. -New algorithms such as set intersection and segmented reduction have also been - added. -Lastly, improvements to the robustness of the CUDA backend ensure correctness - across a broad set of (uncommon) use cases. - -## Breaking Changes - -- `thrust::gather`'s interface was incorrect and has been removed. - The old interface is deprecated but will be preserved for Thrust version 1.2 - at `thrust::deprecated::gather` and `thrust::deprecated::gather_if`. - The new interface is provided at `thrust::next::gather` and - `thrust::next::gather_if`. - The new interface will be promoted to `thrust::` in Thrust version 1.3. - For more details, please refer to [this thread](http://groups.google.com/group/thrust-users/browse_thread/thread/f5f0583cb97b51fd). -- The `thrust::sorting` namespace has been deprecated in favor of the top-level - sorting functions, such as `thrust::sort` and `thrust::sort_by_key`. -- Removed support for `thrust::equal` between host & device sequences. -- Removed support for `thrust::scatter` between host & device sequences. - -## New Features - -- Algorithms: - - `thrust::reduce_by_key` - - `thrust::set_intersection` - - `thrust::unique_copy` - - `thrust::unique_by_key` - - `thrust::unique_copy_by_key` -- Types -- Random Number Generation: - - `thrust::discard_block_engine` - - `thrust::default_random_engine` - - `thrust::linear_congruential_engine` - - `thrust::linear_feedback_shift_engine` - - `thrust::subtract_with_carry_engine` - - `thrust::xor_combine_engine` - - `thrust::minstd_rand` - - `thrust::minstd_rand0` - - `thrust::ranlux24` - - `thrust::ranlux48` - - `thrust::ranlux24_base` - - `thrust::ranlux48_base` - - `thrust::taus88` - - `thrust::uniform_int_distribution` - - `thrust::uniform_real_distribution` - - `thrust::normal_distribution` (experimental) -- Function Objects: - - `thrust::project1st` - - `thrust::project2nd` -- `thrust::tie` -- Fancy Iterators: - - `thrust::permutation_iterator` - - `thrust::reverse_iterator` -- Vector Functions: - - `operator!=` - - `rbegin` - - `crbegin` - - `rend` - - `crend` - - `data` - - `shrink_to_fit` -- Device Support: - - Multicore CPUs via OpenMP. - - Fermi-class GPUs. - - Ocelot virtual machines. -- Support for NVCC 3.0. - -## New Examples - -- `cpp_integration` -- `histogram` -- `mode` -- `monte_carlo` -- `monte_carlo_disjoint_sequences` -- `padded_grid_reduction` -- `permutation_iterator` -- `row_sum` -- `run_length_encoding` -- `segmented_scan` -- `stream_compaction` -- `summary_statistics` -- `transform_iterator` -- `word_count` - -## Other Enhancements - -- Integer sorting performance is improved when max is large but (max - min) is - small and when min is negative -- Performance of `thrust::inclusive_scan` and `thrust::exclusive_scan` is - improved by 20-25% for primitive types. - -## Bug Fixes - -- #8 cause a compiler error if the required compiler is not found rather than a - mysterious error at link time -- #42 device_ptr & device_reference are classes rather than structs, - eliminating warnings on certain platforms -- #46 gather & scatter handle any space iterators correctly -- #51 thrust::experimental::arch functions gracefully handle unrecognized GPUs -- #52 avoid collisions with common user macros such as BLOCK_SIZE -- #62 provide better documentation for device_reference -- #68 allow built-in CUDA vector types to work with device_vector in pure C++ - mode -- #102 eliminated a race condition in device_vector::erase -- various compilation warnings eliminated - -## Known Issues - -- inclusive_scan & exclusive_scan may fail with very large types -- MSVC may fail to compile code using both sort and binary search algorithms -- uninitialized_fill & uninitialized_copy dispatch constructors on the host - rather than the device -- #109 some algorithms may exhibit poor performance with the OpenMP backend - with large numbers (>= 6) of CPU threads -- default_random_engine::discard is not accelerated with nvcc 2.3 - -## Acknowledgments - -- Thanks to Gregory Diamos for contributing a CUDA implementation of - set_intersection -- Thanks to Ryuta Suzuki & Gregory Diamos for rigorously testing Thrust's unit - tests and examples against Ocelot -- Thanks to Tom Bradley for contributing an implementation of normal_distribution -- Thanks to Joseph Rhoads for contributing the example summary_statistics - -# Thrust 1.1.1 - -## Summary - -Small fixes for compatibility with CUDA Toolkit 2.3a and Mac OSX Snow Leopard. - -# Thrust 1.1.0 - -## Summary - -Thrust 1.1.0 introduces fancy iterators, binary search functions, and several - specialized reduction functions. -Experimental support for segmented scans has also been added. - -## Breaking Changes - -- `thrust::counting_iterator` has been moved into the `thrust` namespace - (previously `thrust::experimental`). - -## New Features - -- Algorithms: - - `thrust::copy_if` - - `thrust::lower_bound` - - `thrust::upper_bound` - - `thrust::vectorized lower_bound` - - `thrust::vectorized upper_bound` - - `thrust::equal_range` - - `thrust::binary_search` - - `thrust::vectorized binary_search` - - `thrust::all_of` - - `thrust::any_of` - - `thrust::none_of` - - `thrust::minmax_element` - - `thrust::advance` - - `thrust::inclusive_segmented_scan` (experimental) - - `thrust::exclusive_segmented_scan` (experimental) -- Types: - - `thrust::pair` - - `thrust::tuple` - - `thrust::device_malloc_allocator` -- Fancy Iterators: - - `thrust::constant_iterator` - - `thrust::counting_iterator` - - `thrust::transform_iterator` - - `thrust::zip_iterator` - -## New Examples - -- Computing the maximum absolute difference between vectors. -- Computing the bounding box of a two-dimensional point set. -- Sorting multiple arrays together (lexicographical sorting). -- Constructing a summed area table. -- Using `thrust::zip_iterator` to mimic an array of structs. -- Using `thrust::constant_iterator` to increment array values. - -## Other Enhancements - -- Added pinned memory allocator (experimental). -- Added more methods to host_vector & device_vector (issue #4). -- Added variant of remove_if with a stencil argument (issue #29). -- Scan and reduce use cudaFuncGetAttributes to determine grid size. -- Exceptions are reported when temporary device arrays cannot be allocated. - -## Bug Fixes - -- #5: Make vector work for larger data types -- #9: stable_partition_copy doesn't respect OutputIterator concept semantics -- #10: scans should return OutputIterator -- #16: make algorithms work for larger data types -- #27: Dispatch radix_sort even when comp=less is explicitly provided - -## Known Issues - -- Using functors with Thrust entry points may not compile on Mac OSX with gcc - 4.0.1. -- `thrust::uninitialized_copy` and `thrust::uninitialized_fill` dispatch - constructors on the host rather than the device. -- `thrust::inclusive_scan`, `thrust::inclusive_scan_by_key`, - `thrust::exclusive_scan`, and `thrust::exclusive_scan_by_key` may fail when - used with large types with the CUDA Toolkit 3.1. - -# Thrust 1.0.0 - -## Breaking Changes - -- Rename top level namespace `komrade` to `thrust`. -- Move `thrust::partition_copy` & `thrust::stable_partition_copy` into - `thrust::experimental` namespace until we can easily provide the standard - interface. -- Rename `thrust::range` to `thrust::sequence` to avoid collision with - Boost.Range. -- Rename `thrust::copy_if` to `thrust::copy_when` due to semantic differences - with C++0x `std::copy_if`. - -## New Features - -- Add C++0x style `cbegin` & `cend` methods to `thrust::host_vector` and - `thrust::device_vector`. -- Add `thrust::transform_if` function. -- Add stencil versions of `thrust::replace_if` & `thrust::replace_copy_if`. -- Allow `counting_iterator` to work with `thrust::for_each`. -- Allow types with constructors in comparison `thrust::sort` and - `thrust::reduce`. - -## Other Enhancements - -- `thrust::merge_sort` and `thrust::stable_merge_sort` are now 2x to 5x faster - when executed on the parallel device. - -## Bug Fixes - -- Komrade 6: Workaround an issue where an incremented iterator causes NVCC to - crash. -- Komrade 7: Fix an issue where `const_iterator`s could not be passed to - `thrust::transform`. - diff --git a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/CMakeLists.txt b/IfcPlusPlus/src/external/manifold/src/third_party/thrust/CMakeLists.txt deleted file mode 100644 index 606426b60..000000000 --- a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/CMakeLists.txt +++ /dev/null @@ -1,138 +0,0 @@ -# 3.15 is the minimum for including the project with add_subdirectory. -# 3.17 for building the project's standalone tests/examples/etc. -# 3.18.3 for C++17 + CUDA -cmake_minimum_required(VERSION 3.15) - -# Remove this when we use the new CUDA_ARCHITECTURES properties with both -# nvcc and nvc++. -if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.18) - cmake_policy(SET CMP0104 OLD) -endif() - -project(Thrust NONE) - -# Determine whether Thrust is the top-level project or included into -# another project via add_subdirectory() -if ("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_LIST_DIR}") - set(THRUST_TOPLEVEL_PROJECT ON) -else() - set(THRUST_TOPLEVEL_PROJECT OFF) -endif() - -# This must be done before any languages are enabled: -if (THRUST_TOPLEVEL_PROJECT) - include(cmake/ThrustCompilerHacks.cmake) -endif() - -# This must appear after our Compiler Hacks or else CMake will delete the cache -# and reconfigure from scratch. -# This must also appear before the installation rules, as it is required by the -# GNUInstallDirs CMake module. -enable_language(CXX) - -# Optionally include installation rules for non-top-level builds: -option(THRUST_ENABLE_INSTALL_RULES "Enable installation of Thrust" ${THRUST_TOPLEVEL_PROJECT}) -if (THRUST_ENABLE_INSTALL_RULES) - include(cmake/ThrustInstallRules.cmake) -endif() - -# Support adding Thrust to a parent project via add_subdirectory. -# See examples/cmake/add_subdir/CMakeLists.txt for details. -if (NOT THRUST_TOPLEVEL_PROJECT) - include(cmake/ThrustAddSubdir.cmake) - return() -endif() - -# We use 3.17 features when building our tests, etc. -cmake_minimum_required(VERSION 3.17) - -option(THRUST_ENABLE_HEADER_TESTING "Test that all public headers compile." "ON") -option(THRUST_ENABLE_TESTING "Build Thrust testing suite." "ON") -option(THRUST_ENABLE_EXAMPLES "Build Thrust examples." "ON") -option(THRUST_ENABLE_BENCHMARKS "Build Thrust runtime benchmarks." "OFF") -option(THRUST_INCLUDE_CUB_CMAKE "Build CUB tests and examples. (Requires CUDA)." "OFF") - -# Mark this option as advanced for now. We'll revisit this later once the new -# benchmarks are ready. For now, we just need to expose a way to compile -# bench.cu from CMake for NVIDIA's internal builds. -mark_as_advanced(THRUST_ENABLE_BENCHMARKS) - -# Check if we're actually building anything before continuing. If not, no need -# to search for deps, etc. This is a common approach for packagers that just -# need the install rules. See GH issue NVIDIA/thrust#1211. -if (NOT (THRUST_ENABLE_HEADER_TESTING OR - THRUST_ENABLE_TESTING OR - THRUST_ENABLE_EXAMPLES OR - THRUST_ENABLE_BENCHMARKS OR - THRUST_INCLUDE_CUB_CMAKE)) - return() -endif() - -include(cmake/AppendOptionIfAvailable.cmake) -include(cmake/ThrustBuildCompilerTargets.cmake) -include(cmake/ThrustBuildTargetList.cmake) -include(cmake/ThrustFindThrust.cmake) -include(cmake/ThrustMultiConfig.cmake) -include(cmake/ThrustUtilities.cmake) - -# Add cache string options for CMAKE_BUILD_TYPE and default to RelWithDebInfo. -if ("" STREQUAL "${CMAKE_BUILD_TYPE}") - set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING "Choose the type of build." FORCE) - - set_property( - CACHE CMAKE_BUILD_TYPE - PROPERTY STRINGS Debug Release RelWithDebInfo MinSizeRel - ) -endif () - -# Disable compiler extensions: -set(CMAKE_CXX_EXTENSIONS OFF) - -# Where to put build outputs. Use CMAKE_BINARY_DIR so they'll show up in the -# top-level project's dir when building Thrust via add_subdirectory. -set(THRUST_LIBRARY_OUTPUT_DIR "${CMAKE_BINARY_DIR}/lib") -set(THRUST_EXECUTABLE_OUTPUT_DIR "${CMAKE_BINARY_DIR}/bin") - -thrust_configure_multiconfig() -thrust_find_thrust() -thrust_build_compiler_targets() -thrust_update_system_found_flags() -if (THRUST_CUDA_FOUND) - include(cmake/ThrustCudaConfig.cmake) -endif() -thrust_build_target_list() - -message(STATUS "CPP system found? ${THRUST_CPP_FOUND}") -message(STATUS "CUDA system found? ${THRUST_CUDA_FOUND}") -message(STATUS "TBB system found? ${THRUST_TBB_FOUND}") -message(STATUS "OMP system found? ${THRUST_OMP_FOUND}") - -if (THRUST_ENABLE_HEADER_TESTING) - include(cmake/ThrustHeaderTesting.cmake) -endif() - -# Both testing and examples use ctest -if (THRUST_ENABLE_TESTING OR THRUST_ENABLE_EXAMPLES) - include(CTest) - enable_testing() -endif() - -if (THRUST_ENABLE_TESTING) - add_subdirectory(testing) -endif() - -if (THRUST_ENABLE_EXAMPLES) - add_subdirectory(examples) -endif() - -if (THRUST_ENABLE_BENCHMARKS) - add_subdirectory(internal/benchmark) -endif() - -if (THRUST_INCLUDE_CUB_CMAKE AND THRUST_CUDA_FOUND) - set(CUB_IN_THRUST ON) - # CUB's path is specified generically to support both GitHub and Perforce - # source tree layouts. The include directory used by cub-config.cmake - # for source layouts is the same as the project root. - add_subdirectory("${_CUB_INCLUDE_DIR}" dependencies/cub) -endif() diff --git a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/CODE_OF_CONDUCT.md b/IfcPlusPlus/src/external/manifold/src/third_party/thrust/CODE_OF_CONDUCT.md deleted file mode 100644 index 8c56af363..000000000 --- a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,96 +0,0 @@ -# Code of Conduct - -## Overview - -This document defines the Code of Conduct followed and enforced for NVIDIA C++ - Core Compute Libraries. - -### Intended Audience - -* Community -* Developers -* Project Leads - -## Our Pledge - -In the interest of fostering an open and welcoming environment, we as - contributors and maintainers pledge to making participation in our project and - our community a harassment-free experience for everyone, regardless of age, - body size, disability, ethnicity, sex characteristics, gender identity and - expression, level of experience, education, socio-economic status, nationality, - personal appearance, race, religion, or sexual identity and orientation. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment include: - -- Using welcoming and inclusive language. -- Being respectful of differing viewpoints and experiences. -- Gracefully accepting constructive criticism. -- Focusing on what is best for the community. -- Showing empathy towards other community members. - -Examples of unacceptable behavior by participants include: - -- The use of sexualized language or imagery and unwelcome sexual attention or - advances. -- Trolling, insulting/derogatory comments, and personal or political attacks. -- Public or private harassment. -- Publishing others’ private information, such as a physical or electronic - address, without explicit permission. -- Other conduct which could reasonably be considered inappropriate. - -## Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable - behavior and are expected to take appropriate and fair corrective action in - response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or - reject comments, commits, code, wiki edits, issues, and other contributions - that are not aligned to this Code of Conduct, or to ban temporarily or - permanently any contributor for other behaviors that they deem inappropriate, - threatening, offensive, or harmful. - -## Scope - -This Code of Conduct applies both within project spaces and in public spaces - when an individual is representing the project or its community. -Examples of representing a project or community include using an official - project email address, posting via an official social media account, or acting - as an appointed representative at an online or offline event. -Representation of a project may be further defined and clarified by project - maintainers. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be - reported by contacting [cpp-conduct@nvidia.com](mailto:cpp-conduct@nvidia.com). -All complaints will be reviewed and investigated and will result in a response - that is deemed necessary and appropriate to the circumstances. -The project team is obligated to maintain confidentiality with regard to the - reporter of an incident. -Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good - faith may face temporary or permanent repercussions as determined by other - members of the project’s leadership. - -## Attribution - -This Code of Conduct was taken from the [NVIDIA RAPIDS] project, which was - adapted from the [Contributor Covenant version 1.4]. - -Please see this [FAQ] for answers to common questions about this Code of Conduct. - -## Contact - -Please email [cpp-conduct@nvidia.com] for any Code of Conduct related matters. - - -[cpp-conduct@nvidia.com]: mailto:cpp-conduct@nvidia.com - -[FAQ]: https://www.contributor-covenant.org/faq - -[NVIDIA RAPIDS]: https://docs.rapids.ai/resources/conduct/ -[Contributor Covenant version 1.4]: https://www.contributor-covenant.org/version/1/4/code-of-conduct.html diff --git a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/CONTRIBUTING.md b/IfcPlusPlus/src/external/manifold/src/third_party/thrust/CONTRIBUTING.md deleted file mode 100644 index 705fa5ab1..000000000 --- a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/CONTRIBUTING.md +++ /dev/null @@ -1,569 +0,0 @@ -# Table of Contents - -1. [Contributing to Thrust](#contributing-to-thrust) -1. [CMake Options](#cmake-options) -1. [Development Model](#development-model) - -# Contributing to Thrust - -Thrust uses Github to manage all open-source development, including bug -tracking, pull requests, and design discussions. This document details how to get -started as a Thrust contributor. - -An overview of this process is: - -1. [Clone the Thrust repository](#clone-the-thrust-repository) -1. [Setup a fork of Thrust](#setup-a-fork-of-thrust) -1. [Setup your environment](#setup-your-environment) -1. [Create a development branch](#create-a-development-branch) -1. [Local development loop](#local-development-loop) -1. [Push development branch to your fork](#push-development-branch-to-your-fork) -1. [Create pull request](#create-pull-request) -1. [Address feedback and update pull request](#address-feedback-and-update-pull-request) -1. [When your PR is approved...](#when-your-pr-is-approved) - -## Clone the Thrust Repository - -To get started, clone the main repository to your local computer. Thrust should -be cloned recursively to setup the CUB submodule (required for `CUDA` -acceleration). - -``` -git clone --recursive https://github.com/NVIDIA/thrust.git -cd thrust -``` - -## Setup a Fork of Thrust - -You'll need a fork of Thrust on Github to create a pull request. To setup your -fork: - -1. Create a Github account (if needed) -2. Go to [the Thrust Github page](https://github.com/NVIDIA/thrust) -3. Click "Fork" and follow any prompts that appear. - -Once your fork is created, setup a new remote repo in your local Thrust clone: - -``` -git remote add github-fork git@github.com:/thrust.git -``` - -If you need to modify CUB, too, go to -[the CUB Github page](https://github.com/NVIDIA/cub) and repeat this process. -Create CUB's `github-fork` remote in the `thrust/dependencies/cub` submodule. - -## Setup Your Environment - -### Git Environment - -If you haven't already, this is a good time to tell git who you are. This -information is used to fill out authorship information on your git commits. - -``` -git config --global user.name "John Doe" -git config --global user.email johndoe@example.com -``` - -### Configure CMake builds - -Thrust uses [CMake](https://www.cmake.org) for its primary build system. To -configure, build, and test your checkout of Thrust: - -``` -# Create build directory: -mkdir build -cd build - -# Configure -- use one of the following: -cmake .. # Command line interface -cmake -DTHRUST_INCLUDE_CUB_CMAKE=ON .. # Enables CUB development targets -ccmake .. # ncurses GUI (Linux only) -cmake-gui # Graphical UI, set source/build directories in the app - -# Build: -cmake --build . -j # invokes make (or ninja, etc) - -# Run tests and examples: -ctest -``` - -See [CMake Options](#cmake-options) for details on customizing the build. To -enable CUB tests and examples, set the `THRUST_INCLUDE_CUB_CMAKE` option to -`ON`. Additional CMake options for CUB are listed -[here](https://github.com/NVIDIA/cub/blob/main/CONTRIBUTING.md#cmake-options). - -## Create a Development Branch - -All work should be done in a development branch (also called a "topic branch") -and not directly in the `main` branch. This makes it easier to manage multiple -in-progress patches at once, and provides a descriptive label for your patch -as it passes through the review system. - -To create a new branch based on the current `main`: - -``` -# Checkout local main branch: -cd /path/to/thrust/sources -git checkout main - -# Sync local main branch with github: -git pull - -# Create a new branch named `my_descriptive_branch_name` based on main: -git checkout -b my_descriptive_branch_name - -# Verify that the branch has been created and is currently checked out: -git branch -``` - -Thrust branch names should follow a particular pattern: - -- For new features, name the branch `feature/` -- For bugfixes associated with a github issue, use `bug/github/-` - - Internal nvidia and gitlab bugs should use `nvidia` or `gitlab` in place of - `github`. - -If you plan to work on CUB as part of your patch, repeat this process in the -`thrust/dependencies/cub` submodule. - -## Local Development Loop - -### Edit, Build, Test, Repeat - -Once the topic branch is created, you're all set to start working on Thrust -code. Make some changes, then build and test them: - -``` -# Implement changes: -cd /path/to/thrust/sources -emacs thrust/some_file.h # or whatever editor you prefer - -# Create / update a unit test for your changes: -emacs testing/some_test.cu - -# Check that everything builds and tests pass: -cd /path/to/thrust/build/directory -cmake --build . -j -ctest -``` - -### Creating a Commit - -Once you're satisfied with your patch, commit your changes: - -#### Thrust-only Changes - -``` -# Manually add changed files and create a commit: -cd /path/to/thrust -git add thrust/some_file.h -git add testing/some_test.cu -git commit - -# Or, if possible, use git-gui to review your changes while building your patch: -git gui -``` - -#### Thrust and CUB Changes - -``` -# Create CUB patch first: -cd /path/to/thrust/dependencies/cub -# Manually add changed files and create a commit: -git add cub/some_file.cuh -git commit - -# Create Thrust patch, including submodule update: -cd /path/to/thrust/ -git add dependencies/cub # Updates submodule info -git add thrust/some_file.h -git add testing/some_test.cu -git commit - -# Or, if possible, use git-gui to review your changes while building your patch: -cd /path/to/thrust/dependencies/cub -git gui -cd /path/to/thrust -git gui # Include dependencies/cub as part of your commit - -``` - -#### Writing a Commit Message - -Your commit message will communicate the purpose and rationale behind your -patch to other developers, and will be used to populate the initial description -of your Github pull request. - -When writing a commit message, the following standard format should be used, -since tools in the git ecosystem are designed to parse this correctly: - -``` -First line of commit message is a short summary (<80 char) - -Detailed description of change begins on third line. This portion can -span multiple lines, try to manually wrap them at something reasonable. - -Blank lines can be used to separate multiple paragraphs in the description. - -If your patch is associated with another pull request or issue in the main -Thrust repository, you should reference it with a `#` symbol, e.g. -#1023 for issue 1023. - -For issues / pull requests in a different github repo, reference them using -the full syntax, e.g. NVIDIA/cub#4 for issue 4 in the NVIDIA/cub repo. - -Markdown is recommended for formatting more detailed messages, as these will -be nicely rendered on Github, etc. -``` - -## Push Development Branch to your Fork - -Once you've committed your changes to a local development branch, it's time to -push them to your fork: - -``` -cd /path/to/thrust/checkout -git checkout my_descriptive_branch_name # if not already checked out -git push --set-upstream github-fork my_descriptive_branch_name -``` - -`--set-upstream github-fork` tells git that future pushes/pulls on this branch -should target your `github-fork` remote by default. - -If have CUB changes to commit as part of your patch, repeat this process in the -`thrust/dependencies/cub` submodule. - -## Create Pull Request - -To create a pull request for your freshly pushed branch, open your github fork -in a browser by going to `https://www.github.com//thrust`. A -prompt may automatically appear asking you to create a pull request if you've -recently pushed a branch. - -If there's no prompt, go to "Code" > "Branches" and click the appropriate -"New pull request" button for your branch. - -If you would like a specific developer to review your patch, feel free to -request them as a reviewer at this time. - -The Thrust team will review your patch, test it on NVIDIA's internal CI, and -provide feedback. - - -If have CUB changes to commit as part of your patch, repeat this process with -your CUB branch and fork. - -## Address Feedback and Update Pull Request - -If the reviewers request changes to your patch, use the following process to -update the pull request: - -``` -# Make changes: -cd /path/to/thrust/sources -git checkout my_descriptive_branch_name -emacs thrust/some_file.h -emacs testing/some_test.cu - -# Build + test -cd /path/to/thrust/build/directory -cmake --build . -j -ctest - -# Amend commit: -cd /path/to/thrust/sources -git add thrust/some_file.h -git add testing/some_test.cu -git commit --amend -# Or -git gui # Check the "Amend Last Commit" box - -# Update the branch on your fork: -git push -f -``` - -At this point, the pull request should show your recent changes. - -If have CUB changes to commit as part of your patch, repeat this process in the -`thrust/dependencies/cub` submodule, and be sure to include any CUB submodule -updates as part of your commit. - -## When Your PR is Approved - -Once your pull request is approved by the Thrust team, no further action is -needed from you. We will handle integrating it since we must coordinate changes -to `main` with NVIDIA's internal perforce repository. - -# CMake Options - -A Thrust build is configured using CMake options. These may be passed to CMake -using - -``` -cmake -D= /path/to/thrust/sources -``` - -or configured interactively with the `ccmake` or `cmake-gui` interfaces. - -Thrust supports two build modes. By default, a single configuration is built -that targets a specific host system, device system, and C++ dialect. -When `THRUST_ENABLE_MULTICONFIG` is `ON`, multiple configurations -targeting a variety of systems and dialects are generated. - -The CMake options are divided into these categories: - -1. [Generic CMake Options](#generic-cmake-options): Options applicable to all - Thrust builds. -1. [Single Config CMake Options](#single-config-cmake-options) Options - applicable only when `THRUST_ENABLE_MULTICONFIG` is disabled. -1. [Multi Config CMake Options](#multi-config-cmake-options) Options applicable - only when `THRUST_ENABLE_MULTICONFIG` is enabled. -1. [CUDA Specific CMake Options](#cuda-specific-cmake-options) Options that - control CUDA compilation. Only available when one or more configurations - targets the CUDA system. -1. [TBB Specific CMake Options](#tbb-specific-cmake-options) Options that - control TBB compilation. Only available when one or more configurations - targets the TBB system. - -## Generic CMake Options - -- `CMAKE_BUILD_TYPE={Release, Debug, RelWithDebInfo, MinSizeRel}` - - Standard CMake build option. Default: `RelWithDebInfo` -- `THRUST_ENABLE_HEADER_TESTING={ON, OFF}` - - Whether to test compile public headers. Default is `ON`. -- `THRUST_ENABLE_TESTING={ON, OFF}` - - Whether to build unit tests. Default is `ON`. -- `THRUST_ENABLE_EXAMPLES={ON, OFF}` - - Whether to build examples. Default is `ON`. -- `THRUST_ENABLE_MULTICONFIG={ON, OFF}` - - Toggles single-config and multi-config modes. Default is `OFF` (single config). -- `THRUST_ENABLE_EXAMPLE_FILECHECK={ON, OFF}` - - Enable validation of example outputs using the LLVM FileCheck utility. - Default is `OFF`. -- `THRUST_ENABLE_INSTALL_RULES={ON, OFF}` - - If true, installation rules will be generated for thrust. Default is `ON`. - -## Single Config CMake Options - -- `THRUST_HOST_SYSTEM={CPP, TBB, OMP}` - - Selects the host system. Default: `CPP` -- `THRUST_DEVICE_SYSTEM={CUDA, TBB, OMP, CPP}` - - Selects the device system. Default: `CUDA` -- `THRUST_CPP_DIALECT={11, 14, 17}` - - Selects the C++ standard dialect to use. Default is `14` (C++14). - -## Multi Config CMake Options - -- `THRUST_MULTICONFIG_ENABLE_DIALECT_CPPXX={ON, OFF}` - - Toggle whether a specific C++ dialect will be targeted. - - Possible values of `XX` are `{11, 14, 17}`. - - By default, only C++14 is enabled. -- `THRUST_MULTICONFIG_ENABLE_SYSTEM_XXXX={ON, OFF}` - - Toggle whether a specific system will be targeted. - - Possible values of `XXXX` are `{CPP, CUDA, TBB, OMP}` - - By default, only `CPP` and `CUDA` are enabled. -- `THRUST_MULTICONFIG_WORKLOAD={SMALL, MEDIUM, LARGE, FULL}` - - Restricts the host/device combinations that will be targeted. - - By default, the `SMALL` workload is used. - - The full cross product of `host x device` systems results in 12 - configurations, some of which are more important than others. - This option can be used to prune some of the less important ones. - - `SMALL`: (3 configs) Minimal coverage and validation of each device system against the `CPP` host. - - `MEDIUM`: (6 configs) Cheap extended coverage. - - `LARGE`: (8 configs) Expensive extended coverage. Includes all useful build configurations. - - `FULL`: (12 configs) The complete cross product of all possible build configurations. - -| Config | Workloads | Value | Expense | Note | -|----------|-----------|------------|-----------|------------------------------| -| CPP/CUDA | `F L M S` | Essential | Expensive | Validates CUDA against CPP | -| CPP/OMP | `F L M S` | Essential | Cheap | Validates OMP against CPP | -| CPP/TBB | `F L M S` | Essential | Cheap | Validates TBB against CPP | -| CPP/CPP | `F L M ` | Important | Cheap | Tests CPP as device | -| OMP/OMP | `F L M ` | Important | Cheap | Tests OMP as host | -| TBB/TBB | `F L M ` | Important | Cheap | Tests TBB as host | -| TBB/CUDA | `F L ` | Important | Expensive | Validates TBB/CUDA interop | -| OMP/CUDA | `F L ` | Important | Expensive | Validates OMP/CUDA interop | -| TBB/OMP | `F ` | Not useful | Cheap | Mixes CPU-parallel systems | -| OMP/TBB | `F ` | Not useful | Cheap | Mixes CPU-parallel systems | -| TBB/CPP | `F ` | Not Useful | Cheap | Parallel host, serial device | -| OMP/CPP | `F ` | Not Useful | Cheap | Parallel host, serial device | - -## CUDA Specific CMake Options - -- `THRUST_INCLUDE_CUB_CMAKE={ON, OFF}` - - If enabled, the CUB project will be built as part of Thrust. Default is - `OFF`. - - This adds CUB tests, etc. Useful for working on both CUB and Thrust - simultaneously. - - CUB configurations will be generated for each C++ dialect targeted by - the current Thrust build. -- `THRUST_INSTALL_CUB_HEADERS={ON, OFF}` - - If enabled, the CUB project's headers will be installed through Thrust's - installation rules. Default is `ON`. - - This option depends on `THRUST_ENABLE_INSTALL_RULES`. -- `THRUST_ENABLE_COMPUTE_XX={ON, OFF}` - - Controls the targeted CUDA architecture(s) - - Multiple options may be selected when using NVCC as the CUDA compiler. - - Valid values of `XX` are: - `{35, 37, 50, 52, 53, 60, 61, 62, 70, 72, 75, 80}` - - Default value depends on `THRUST_DISABLE_ARCH_BY_DEFAULT`: -- `THRUST_ENABLE_COMPUTE_FUTURE={ON, OFF}` - - If enabled, CUDA objects will target the most recent virtual architecture - in addition to the real architectures specified by the - `THRUST_ENABLE_COMPUTE_XX` options. - - Default value depends on `THRUST_DISABLE_ARCH_BY_DEFAULT`: -- `THRUST_DISABLE_ARCH_BY_DEFAULT={ON, OFF}` - - When `ON`, all `THRUST_ENABLE_COMPUTE_*` options are initially `OFF`. - - Default: `OFF` (meaning all architectures are enabled by default) -- `THRUST_ENABLE_TESTS_WITH_RDC={ON, OFF}` - - Whether to enable Relocatable Device Code when building tests. - Default is `OFF`. -- `THRUST_ENABLE_EXAMPLES_WITH_RDC={ON, OFF}` - - Whether to enable Relocatable Device Code when building examples. - Default is `OFF`. - -## TBB Specific CMake Options - -- `THRUST_TBB_ROOT=` - - When the TBB system is requested, set this to the root of the TBB installation - (e.g. the location of `lib/`, `bin/` and `include/` for the TBB libraries). - -# Development Model - -The following is a description of the basic development process that Thrust follows. This is a living -document that will evolve as our process evolves. - -Thrust is distributed in three ways: - - * On GitHub. - * In the NVIDIA HPC SDK. - * In the CUDA Toolkit. - -## Trunk Based Development - -Thrust uses [trunk based development](https://trunkbaseddevelopment.com). There is a single long-lived -branch called `main`. Engineers may create branches for feature development. Such branches always -merge into `main`. There are no release branches. Releases are produced by taking a snapshot of -`main` ("snapping"). After a release has been snapped from `main`, it will never be changed. - -## Repositories - -As Thrust is developed both on GitHub and internally at NVIDIA, there are three main places where code lives: - - * The Source of Truth, the [public Thrust repository](https://github.com/NVIDIA/thrust), referred to as - `github` later in this document. - * An internal GitLab repository, referred to as `gitlab` later in this document. - * An internal Perforce repository, referred to as `perforce` later in this document. - -## Versioning - -Thrust has its own versioning system for releases, independent of the versioning scheme of the NVIDIA -HPC SDK or the CUDA Toolkit. - -Today, Thrust version numbers have a specific [semantic meaning](https://semver.org/). -Releases prior to 1.10.0 largely, but not strictly, followed these semantic meanings. - -The version number for a Thrust release uses the following format: `MMM.mmm.ss-ppp`, where: - - * `THRUST_VERSION_MAJOR`/`MMM`: Major version, up to 3 decimal digits. It is incremented - when changes that are API-backwards-incompatible are made. - * `THRUST_VERSION_MINOR`/`mmm`: Minor version, up to 3 decimal digits. It is incremented when - breaking API, ABI, or semantic changes are made. - * `THRUST_VERSION_SUBMINOR`/`ss`: Subminor version, up to 2 decimal digits. It is incremented - when notable new features or bug fixes or features that are API-backwards-compatible are made. - * `THRUST_PATCH_NUMBER`/`ppp`: Patch number, up to 3 decimal digits. This is no longer used and - will be zero for all future releases. - -The `` header defines `THRUST_*` macros for all of the version components mentioned -above. Additionally, a `THRUST_VERSION` macro is defined, which is an integer literal containing all -of the version components except for `THRUST_PATCH_NUMBER`. - -## Branches and Tags - -The following tag names are used in the Thrust project: - - * `github/nvhpc-X.Y`: the tag that directly corresponds to what has been shipped in the NVIDIA HPC SDK release X.Y. - * `github/cuda-X.Y`: the tag that directly corresponds to what has been shipped in the CUDA Toolkit release X.Y. - * `github/A.B.C`: the tag that directly corresponds to Thrust version A.B.C. - * `github/A.B.C-rcN`: the tag that directly corresponds to Thrust version A.B.C release candidate N. - -The following branch names are used in the Thrust project: - - * `github/main`: the Source of Truth development branch of Thrust. - * `github/old-master`: the old Source of Truth branch, before unification of public and internal repositories. - * `github/feature/`: feature branch for a feature under development. - * `github/bug//-`: bug fix branch, where `bug-system` is `github` or `nvidia`. - * `gitlab/main`: mirror of `github/main`. - * `perforce/private`: mirrored `github/main`, plus files necessary for internal NVIDIA testing systems. - -On the rare occasion that we cannot do work in the open, for example when developing a change specific to an -unreleased product, these branches may exist on `gitlab` instead of `github`. By default, everything should be -in the open on `github` unless there is a strong motivation for it to not be open. - -# Release Process - -This section is a work in progress. - -## Update Compiler Explorer - -Thrust and CUB are bundled together on -[Compiler Explorer](https://www.godbolt.org/) (CE) as libraries for the CUDA -language. When releasing a new version of these projects, CE will need to be -updated. - -There are two files in two repos that need to be updated: - -### libraries.yaml - -- Repo: https://github.com/compiler-explorer/infra -- Path: bin/yaml/libraries.yaml - -This file tells CE how to pull in library files and defines which versions to -fetch. Look for the `thrustcub:` section: - -```yaml - thrustcub: - type: github - method: clone_branch - repo: NVIDIA/thrust - check_file: dependencies/cub/cub/cub.cuh - targets: - - 1.9.9 - - 1.9.10 - - 1.9.10-1 - - 1.10.0 -``` - -Simply add the new version tag to list of `targets:`. This will check out the -specified tag to `/opt/compiler-explorer/libs/thrustcub//`. - -### cuda.amazon.properties - -- Repo: https://github.com/compiler-explorer/compiler-explorer -- File: etc/config/cuda.amazon.properties - -This file defines the library versions displayed in the CE UI and maps them -to a set of include directories. Look for the `libs.thrustcub` section: - -```yaml -libs.thrustcub.name=Thrust+CUB -libs.thrustcub.description=CUDA collective and parallel algorithms -libs.thrustcub.versions=trunk:109090:109100:109101:110000 -libs.thrustcub.url=http://www.github.com/NVIDIA/thrust -libs.thrustcub.versions.109090.version=1.9.9 -libs.thrustcub.versions.109090.path=/opt/compiler-explorer/libs/thrustcub/1.9.9:/opt/compiler-explorer/libs/thrustcub/1.9.9/dependencies/cub -libs.thrustcub.versions.109100.version=1.9.10 -libs.thrustcub.versions.109100.path=/opt/compiler-explorer/libs/thrustcub/1.9.10:/opt/compiler-explorer/libs/thrustcub/1.9.10/dependencies/cub -libs.thrustcub.versions.109101.version=1.9.10-1 -libs.thrustcub.versions.109101.path=/opt/compiler-explorer/libs/thrustcub/1.9.10-1:/opt/compiler-explorer/libs/thrustcub/1.9.10-1/dependencies/cub -libs.thrustcub.versions.110000.version=1.10.0 -libs.thrustcub.versions.110000.path=/opt/compiler-explorer/libs/thrustcub/1.10.0:/opt/compiler-explorer/libs/thrustcub/1.10.0/dependencies/cub -libs.thrustcub.versions.trunk.version=trunk -libs.thrustcub.versions.trunk.path=/opt/compiler-explorer/libs/thrustcub/trunk:/opt/compiler-explorer/libs/thrustcub/trunk/dependencies/cub -``` - -Add a new version identifier to the `libs.thrustcub.versions` key, using the -convention `X.Y.Z-W -> XXYYZZWW`. Then add a corresponding UI label (the -`version` key) and set of colon-separated include paths for Thrust and CUB -(`path`). The version used in the `path` entries must exactly match the tag -specified in `libraries.yaml`. diff --git a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/LICENSE b/IfcPlusPlus/src/external/manifold/src/third_party/thrust/LICENSE deleted file mode 100644 index c22c22563..000000000 --- a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/LICENSE +++ /dev/null @@ -1,249 +0,0 @@ -Unless otherwise noted, Thrust's source code is released under the Apache -License, Version 2.0: - -================================================================================ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -================================================================================ - -Some portions of Thrust may be licensed under other compatible open-source -licenses. Any divergence from the Apache 2 license will be noted in the source -code where applicable. - -Portions under other terms include, but are not limited to: - -================================================================================ - -Various C++ utility classes in Thrust are based on the Boost Iterator, Tuple, -System, and Random Number libraries, which are provided under the Boost Software -License: - - Boost Software License - Version 1.0 - August 17th, 2003 - - Permission is hereby granted, free of charge, to any person or organization - obtaining a copy of the software and accompanying documentation covered by - this license (the "Software") to use, reproduce, display, distribute, - execute, and transmit the Software, and to prepare derivative works of the - Software, and to permit third-parties to whom the Software is furnished to - do so, all subject to the following: - - The copyright notices in the Software and this entire statement, including - the above license grant, this restriction and the following disclaimer, - must be included in all copies of the Software, in whole or in part, and - all derivative works of the Software, unless such copies or derivative - works are solely in the form of machine-executable object code generated by - a source language processor. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT - SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE - FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, - ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. - -================================================================================ - -Portions of the thrust::complex implementation are derived from FreeBSD with the -following terms: - - 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 above copyright - notice[1] unmodified, this list of conditions, and the following - disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - 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. - -[1] Individual copyright notices from the original authors are included in - the relevant source files. - -================================================================================ diff --git a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/Makefile b/IfcPlusPlus/src/external/manifold/src/third_party/thrust/Makefile deleted file mode 100644 index bf421cc2a..000000000 --- a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/Makefile +++ /dev/null @@ -1,161 +0,0 @@ -# Copyright 2010-2020 NVIDIA Corporation. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Makefile for building Thrust unit test driver - -# Force C++11 mode. NVCC will ignore it if the host compiler doesn't support it. -export CXX_STD := c++11 - -export CCCL_ENABLE_DEPRECATIONS := 1 - -export VERBOSE := 1 - -ifndef PROFILE - ifdef VULCAN_TOOLKIT_BASE - include $(VULCAN_TOOLKIT_BASE)/build/getprofile.mk - include $(VULCAN_TOOLKIT_BASE)/build/config/$(PROFILE).mk - else - include ../build/getprofile.mk - include ../build/config/$(PROFILE).mk - endif -endif - -SOLNDIR := . - -ifdef VULCAN_TOOLKIT_BASE - include $(VULCAN_TOOLKIT_BASE)/build/config/DetectOS.mk -else - include ../build/config/DetectOS.mk -endif - -TMP_DIR := built -TMP_PREFIX := $(ROOTDIR) -TMP_ARCH := $(ARCH)_$(PROFILE)_agnostic -THRUST_MKDIR := $(TMP_PREFIX)/$(TMP_DIR)/$(TMP_ARCH)/thrust/mk -THRUST_DIR := $(ROOTDIR)/thrust - -res:=$(shell $(PYTHON) ./generate_mk.py $(THRUST_MKDIR) $(THRUST_DIR)) - -# Use these environment variables to control what gets built: -# -# TEST_ALL -# TEST_UNITTESTS -# TEST_EXAMPLES -# TEST_BENCH -# TEST_OTHER - -ifneq ($(TEST_ALL),) - override TEST_UNITTESTS := 1 - override TEST_EXAMPLES := 1 - override TEST_BENCH := 1 - override TEST_OTHER := 1 -endif - -ifeq ($(TEST_UNITTESTS)$(TEST_EXAMPLES)$(TEST_BENCH)$(TEST_OTHER),) - override TEST_UNITTESTS := 1 - override TEST_EXAMPLES := 1 - override TEST_BENCH := 1 - override TEST_OTHER := 1 -endif - -ifneq ($(TEST_OTHER),) - PROJECTS += internal/build/warningstester -endif - -ifneq ($(TEST_BENCH),) - PROJECTS += internal/benchmark/bench -endif - -ifneq ($(TEST_UNITTESTS),) - # copy existing projects - PROJECTS_COPY := $(PROJECTS) - - # empty PROJECTS - PROJECTS := - - # populate PROJECTS with unit tests. - include $(THRUST_MKDIR)/testing.mk - - # Once PROJECTS is populated with unit tests, re-add the previous projects. - PROJECTS += $(PROJECTS_COPY) -endif - -ifneq ($(TEST_EXAMPLES),) - # Copy existing projects. - PROJECTS_COPY := $(PROJECTS) - - # Empty PROJECTS. - PROJECTS := - - # Populate PROJECTS with examples. - include $(THRUST_MKDIR)/examples.mk - - # Once PROJECTS is populated with examples, re-add the previous projects. - PROJECTS += $(PROJECTS_COPY) -endif - -ifdef VULCAN_TOOLKIT_BASE - include $(VULCAN_TOOLKIT_BASE)/build/common.mk -else - include ../build/common.mk -endif - -ifeq ($(OS), win32) - CREATE_DVS_PACKAGE = $(ZIP) -r built/CUDA-thrust-package.zip bin thrust/internal/test thrust/internal/scripts thrust/internal/benchmark $(DVS_COMMON_TEST_PACKAGE_FILES) - APPEND_H_DVS_PACKAGE = $(ZIP) -rg built/CUDA-thrust-package.zip thrust -9 -i *.h - APPEND_INL_DVS_PACKAGE = $(ZIP) -rg built/CUDA-thrust-package.zip thrust -9 -i *.inl - APPEND_CUH_DVS_PACKAGE = $(ZIP) -rg built/CUDA-thrust-package.zip thrust -9 -i *.cuh - MAKE_DVS_PACKAGE = $(CREATE_DVS_PACKAGE) && $(APPEND_H_DVS_PACKAGE) && $(APPEND_INL_DVS_PACKAGE) && $(APPEND_CUH_DVS_PACKAGE) -else - TAR_FILES = bin thrust/internal/test thrust/internal/scripts thrust/internal/benchmark $(DVS_COMMON_TEST_PACKAGE_FILES) - TAR_FILES += `find -L thrust \( -name "*.cuh" -o -name "*.h" -o -name "*.inl" \)` - MAKE_DVS_PACKAGE = tar -I lbzip2 -chvf built/CUDA-thrust-package.tar.bz2 $(TAR_FILES) -endif - -COPY_CUB_FOR_PACKAGING = rm -rf cub && cp -rp ../cub/cub cub - -DVS_OPTIONS := - -ifneq ($(TARGET_ARCH),$(HOST_ARCH)) - DVS_OPTIONS += TARGET_ARCH=$(TARGET_ARCH) -endif -ifeq ($(TARGET_ARCH),ARMv7) - DVS_OPTIONS += ABITYPE=$(ABITYPE) -endif - -THRUST_DVS_BUILD = release - -pack: - $(COPY_CUB_FOR_PACKAGING) - cd .. && $(MAKE_DVS_PACKAGE) - -dvs: - $(COPY_CUB_FOR_PACKAGING) -# Build the CUDA Runtime in GVS, because GVS has no CUDA Runtime component. -# This is a temporary workaround until the Tegra team adds a CUDA Runtime -# component, which they have promised to do. -ifdef GVS - $(MAKE) $(DVS_OPTIONS) -s -C ../cuda $(THRUST_DVS_BUILD) -endif - $(MAKE) $(DVS_OPTIONS) $(THRUST_DVS_BUILD) THRUST_DVS=1 - cd .. && $(MAKE_DVS_PACKAGE) - -dvs_release: - $(MAKE) dvs THRUST_DVS_BUILD=release - -dvs_debug: - $(MAKE) dvs THRUST_DVS_BUILD=debug - -include $(THRUST_MKDIR)/dependencies.mk - diff --git a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/README.md b/IfcPlusPlus/src/external/manifold/src/third_party/thrust/README.md deleted file mode 100644 index ae148541d..000000000 --- a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/README.md +++ /dev/null @@ -1,246 +0,0 @@ - - -# Thrust: Code at the speed of light - -Thrust is a C++ parallel programming library which resembles the C++ Standard -Library. Thrust's **high-level** interface greatly enhances -programmer **productivity** while enabling performance portability between -GPUs and multicore CPUs. **Interoperability** with established technologies -(such as CUDA, TBB, and OpenMP) facilitates integration with existing -software. Develop **high-performance** applications rapidly with Thrust! - -Thrust is included in the NVIDIA HPC SDK and the CUDA Toolkit. - -## Quick Start - -### Getting the Thrust Source Code - -The CUDA Toolkit provides a recent release of the Thrust source code in -`include/thrust`. This will be suitable for most users. - -Users that wish to contribute to Thrust or try out newer features should -recursively clone the Thrust Github repository: - -``` -git clone --recursive https://github.com/NVIDIA/thrust.git -``` - -### Using Thrust From Your Project - -Thrust is a header-only library; there is no need to build or install the project -unless you want to run the Thrust unit tests. - -For CMake-based projects, we provide a CMake package for use with -`find_package`. See the [CMake README](thrust/cmake/README.md) for more -information. Thrust can also be added via `add_subdirectory` or tools like -the [CMake Package Manager](https://github.com/cpm-cmake/CPM.cmake). - -For non-CMake projects, compile with: -- The Thrust include path (`-I`) -- The CUB include path, if using the CUDA device system (`-I/dependencies/cub/`) -- By default, the CPP host system and CUDA device system are used. - These can be changed using compiler definitions: - - `-DTHRUST_HOST_SYSTEM=THRUST_HOST_SYSTEM_XXX`, - where `XXX` is `CPP` (serial, default), `OMP` (OpenMP), or `TBB` (Intel TBB) - - `-DTHRUST_DEVICE_SYSTEM=THRUST_DEVICE_SYSTEM_XXX`, where `XXX` is - `CPP`, `OMP`, `TBB`, or `CUDA` (default). - -### Examples - -Thrust is best explained through examples. The following source code -generates random numbers serially and then transfers them to a parallel -device where they are sorted. - -```c++ -#include -#include -#include -#include -#include -#include -#include - -int main(void) -{ - // generate 32M random numbers serially - thrust::host_vector h_vec(32 << 20); - std::generate(h_vec.begin(), h_vec.end(), rand); - - // transfer data to the device - thrust::device_vector d_vec = h_vec; - - // sort data on the device (846M keys per second on GeForce GTX 480) - thrust::sort(d_vec.begin(), d_vec.end()); - - // transfer data back to host - thrust::copy(d_vec.begin(), d_vec.end(), h_vec.begin()); - - return 0; -} -``` - -This code sample computes the sum of 100 random numbers in parallel: - -```c++ -#include -#include -#include -#include -#include -#include -#include - -int main(void) -{ - // generate random data serially - thrust::host_vector h_vec(100); - std::generate(h_vec.begin(), h_vec.end(), rand); - - // transfer to device and compute sum - thrust::device_vector d_vec = h_vec; - int x = thrust::reduce(d_vec.begin(), d_vec.end(), 0, thrust::plus()); - return 0; -} -``` - -Additional usage examples can be found in the [`examples/`](examples/) and -[`testing/`](testing/) directories of the Github repo. - -## Documentation Resources - -- [API Reference](https://thrust.github.io/doc/modules.html) -- [Examples](https://github.com/NVIDIA/thrust/tree/main/examples) -- [User Support](https://github.com/NVIDIA/thrust/discussions) - -## CI Status - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -## Supported Compilers - -Thrust is regularly tested using the specified versions of the following -compilers. Unsupported versions may emit deprecation warnings, which can be -silenced by defining THRUST_IGNORE_DEPRECATED_COMPILER during compilation. - -- NVCC 11.0+ -- NVC++ 20.9+ -- GCC 5+ -- Clang 7+ -- MSVC 2019+ (19.20/16.0/14.20) - -## Releases - -Thrust is distributed with the NVIDIA HPC SDK and the CUDA Toolkit in addition -to GitHub. - -See the [changelog](CHANGELOG.md) for details about specific releases. - -| Thrust Release | Included In | -| ----------------- | --------------------------------------- | -| 1.16.0 | TBD | -| 1.15.0 | NVIDIA HPC SDK 22.1 & CUDA Toolkit 11.6 | -| 1.14.0 | NVIDIA HPC SDK 21.9 | -| 1.13.1 | CUDA Toolkit 11.5 | -| 1.13.0 | NVIDIA HPC SDK 21.7 | -| 1.12.1 | CUDA Toolkit 11.4 | -| 1.12.0 | NVIDIA HPC SDK 21.3 | -| 1.11.0 | CUDA Toolkit 11.3 | -| 1.10.0 | NVIDIA HPC SDK 20.9 & CUDA Toolkit 11.2 | -| 1.9.10-1 | NVIDIA HPC SDK 20.7 & CUDA Toolkit 11.1 | -| 1.9.10 | NVIDIA HPC SDK 20.5 | -| 1.9.9 | CUDA Toolkit 11.0 | -| 1.9.8-1 | NVIDIA HPC SDK 20.3 | -| 1.9.8 | CUDA Toolkit 11.0 Early Access | -| 1.9.7-1 | CUDA Toolkit 10.2 for Tegra | -| 1.9.7 | CUDA Toolkit 10.2 | -| 1.9.6-1 | NVIDIA HPC SDK 20.3 | -| 1.9.6 | CUDA Toolkit 10.1 Update 2 | -| 1.9.5 | CUDA Toolkit 10.1 Update 1 | -| 1.9.4 | CUDA Toolkit 10.1 | -| 1.9.3 | CUDA Toolkit 10.0 | -| 1.9.2 | CUDA Toolkit 9.2 | -| 1.9.1-2 | CUDA Toolkit 9.1 | -| 1.9.0-5 | CUDA Toolkit 9.0 | -| 1.8.3 | CUDA Toolkit 8.0 | -| 1.8.2 | CUDA Toolkit 7.5 | -| 1.8.1 | CUDA Toolkit 7.0 | -| 1.8.0 | | -| 1.7.2 | CUDA Toolkit 6.5 | -| 1.7.1 | CUDA Toolkit 6.0 | -| 1.7.0 | CUDA Toolkit 5.5 | -| 1.6.0 | | -| 1.5.3 | CUDA Toolkit 5.0 | -| 1.5.2 | CUDA Toolkit 4.2 | -| 1.5.1 | CUDA Toolkit 4.1 | -| 1.5.0 | | -| 1.4.0 | CUDA Toolkit 4.0 | -| 1.3.0 | | -| 1.2.1 | | -| 1.2.0 | | -| 1.1.1 | | -| 1.1.0 | | -| 1.0.0 | | - -## Development Process - -Thrust uses the [CMake build system](https://cmake.org/) to build unit tests, -examples, and header tests. To build Thrust as a developer, the following -recipe should be followed: - -``` -# Clone Thrust and CUB repos recursively: -git clone --recursive https://github.com/NVIDIA/thrust.git -cd thrust - -# Create build directory: -mkdir build -cd build - -# Configure -- use one of the following: -cmake .. # Command line interface. -ccmake .. # ncurses GUI (Linux only) -cmake-gui # Graphical UI, set source/build directories in the app - -# Build: -cmake --build . -j # invokes make (or ninja, etc) - -# Run tests and examples: -ctest -``` - -By default, a serial `CPP` host system, `CUDA` accelerated device system, and -C++14 standard are used. This can be changed during configuration -- see -[CMake Options](CONTRIBUTING.md#cmake-options) for details. - -More information on configuring your Thrust build and creating a pull request -can be found in [CONTRIBUTING.md](CONTRIBUTING.md). diff --git a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/cub b/IfcPlusPlus/src/external/manifold/src/third_party/thrust/cub deleted file mode 100644 index 484d0aaad..000000000 --- a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/cub +++ /dev/null @@ -1 +0,0 @@ -dependencies/cub/cub \ No newline at end of file diff --git a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/generate_mk.py b/IfcPlusPlus/src/external/manifold/src/third_party/thrust/generate_mk.py deleted file mode 100644 index 84071338c..000000000 --- a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/generate_mk.py +++ /dev/null @@ -1,146 +0,0 @@ -#!/usr/bin/env python -# Generate set of projects mk files. -# Usage: python generate_mk.py PROJECTS_MK_DIR THRUST_SOURCE_DIR -# The program scans through unit tests and examples in THRUST_SOURCE_DIR -# and generates project mk for each of the tests and examples in PROJECTS_MK_DIR -# A single example or unit test source file generates its own executable -# This program is called by a top level Makefile, but can also be used stand-alone for debugging -# This program also generates testing.mk, examples.mk and dependencies.mk -from __future__ import print_function -import sys -import shutil as sh -import os -import glob -import re - -test_template = """ -TEST_SRC := %(TEST_SRC)s -TEST_NAME := %(TEST_NAME)s -include $(ROOTDIR)/thrust/internal/build/generic_test.mk -""" -example_template = """ -EXAMPLE_SRC := %(EXAMPLE_SRC)s -EXAMPLE_NAME := %(EXAMPLE_NAME)s -include $(ROOTDIR)/thrust/internal/build/generic_example.mk -""" - -def Glob(pattern, directory,exclude='\B'): - src = glob.glob(os.path.join(directory,pattern)) - p = re.compile(exclude) - src = [s for s in src if not p.match(s)] - return src - - -def generate_test_mk(mk_path, test_path, group, TEST_DIR): - print('Generating makefiles in "'+mk_path+'" for tests in "'+test_path+'"') - src_cu = Glob("*.cu", test_path, ".*testframework.cu$") - src_cxx = Glob("*.cpp", test_path) - src_cu.sort(); - src_cxx.sort(); - src_all = src_cu + src_cxx; - tests_all = [] - dependencies_all = [] - for s in src_all: - fn = os.path.splitext(os.path.basename(s)); - t = "thrust."+group+"."+fn[0] - e = fn[1] - mkfile = test_template % {"TEST_SRC" : s, "TEST_NAME" : t} - f = open(os.path.join(mk_path,t+".mk"), 'w') - f.write(mkfile) - f.close() - tests_all.append(os.path.join(mk_path,t)) - dependencies_all.append(t+": testframework") - return [tests_all, dependencies_all] - -def generate_example_mk(mk_path, example_path, group, EXAMPLE_DIR): - print('Generating makefiles in "'+mk_path+'" for examples in "'+example_path+'"') - src_cu = Glob("*.cu", example_path) - src_cxx = Glob("*.cpp", example_path) - src_cu.sort(); - src_cxx.sort(); - src_all = src_cu + src_cxx; - examples_all = [] - for s in src_all: - fn = os.path.splitext(os.path.basename(s)); - t = "thrust."+group+"."+fn[0] - e = fn[1] - mkfile = example_template % {"EXAMPLE_SRC" : s, "EXAMPLE_NAME" : t} - f = open(os.path.join(mk_path,t+".mk"), 'w') - f.write(mkfile) - f.close() - examples_all.append(os.path.join(mk_path,t)) - return examples_all - - -## relpath : backported from os.relpath form python 2.6+ -def relpath(path, start): - """Return a relative version of a path""" - - import posixpath - if not path: - raise ValueError("no path specified") - start_list = posixpath.abspath(start).split(posixpath.sep) - path_list = posixpath.abspath(path).split(posixpath.sep) - # Work out how much of the filepath is shared by start and path. - i = len(posixpath.commonprefix([start_list, path_list])) - rel_list = [posixpath.pardir] * (len(start_list)-i) + path_list[i:] - if not rel_list: - return posixpath.curdir - return posixpath.join(*rel_list) - -mk_path=sys.argv[1] -REL_DIR="../../" -if (len(sys.argv) > 2): - root_path=sys.argv[2]; - mk_path = relpath(mk_path, root_path) - REL_DIR = relpath(root_path,mk_path) - -try: - sh.rmtree(mk_path) -except: - pass -os.makedirs(mk_path) - -tests_all, dependencies_all = generate_test_mk(mk_path, "testing/", "test", REL_DIR) -tests_cu, dependencies_cu = generate_test_mk(mk_path, "testing/cuda/", "test.cuda", REL_DIR) -tests_all.extend(tests_cu) -dependencies_all.extend(dependencies_cu) - -testing_mk = "" - -for t in tests_all: - testing_mk += "PROJECTS += "+t+"\n" -testing_mk += "PROJECTS += internal/build/testframework\n" - - -f = open(os.path.join(mk_path,"testing.mk"),'w') -f.write(testing_mk) -f.close() - -dependencies_mk = "" -for d in dependencies_all: - dependencies_mk += d + "\n" - -f = open(os.path.join(mk_path,"dependencies.mk"),'w') -f.write(dependencies_mk) -f.close() - - -examples_mk = "" -examples_all = generate_example_mk(mk_path, "examples/", "example", REL_DIR) -examples_cuda = generate_example_mk(mk_path, "examples/cuda/", "example.cuda", REL_DIR) -examples_all.extend(examples_cuda) -for e in examples_all: - examples_mk += "PROJECTS += "+e+"\n" - -f = open(os.path.join(mk_path,"examples.mk"),'w') -f.write(examples_mk) -f.close() - - - - - - - - diff --git a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/thrust/addressof.h b/IfcPlusPlus/src/external/manifold/src/third_party/thrust/thrust/addressof.h deleted file mode 100644 index d21df0c76..000000000 --- a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/thrust/addressof.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) 2018 NVIDIA Corporation -// Author: Bryce Adelstein Lelbach -// -// Distributed under the Boost Software License v1.0 (boost.org/LICENSE_1_0.txt) - -#pragma once - -#include - -#if THRUST_CPP_DIALECT >= 2011 -# include -#endif - -THRUST_NAMESPACE_BEGIN - -/////////////////////////////////////////////////////////////////////////////// - -/*! Obtains the actual address of the object or function arg, even in presence of overloaded operator&. - */ -template -__host__ __device__ -T* addressof(T& arg) -{ - return reinterpret_cast( - &const_cast(reinterpret_cast(arg)) - ); -} - -/////////////////////////////////////////////////////////////////////////////// - -THRUST_NAMESPACE_END diff --git a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/thrust/adjacent_difference.h b/IfcPlusPlus/src/external/manifold/src/third_party/thrust/thrust/adjacent_difference.h deleted file mode 100644 index e8385c240..000000000 --- a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/thrust/adjacent_difference.h +++ /dev/null @@ -1,244 +0,0 @@ -/* - * Copyright 2008-2013 NVIDIA Corporation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -/*! \file adjacent_difference.h - * \brief Compute difference between consecutive elements of a range - */ - -#pragma once - -#include -#include - -THRUST_NAMESPACE_BEGIN - -/*! \addtogroup transformations Transformations - * \{ - */ - - -/*! \p adjacent_difference calculates the differences of adjacent elements in the - * range [first, last). That is, \*first is assigned to - * \*result, and, for each iterator \p i in the range - * [first + 1, last), the difference of \*i and *(i - 1) - * is assigned to \*(result + (i - first)). - * - * This version of \p adjacent_difference uses operator- to calculate - * differences. - * - * The algorithm's execution is parallelized as determined by \p exec. - * - * \param exec The execution policy to use for parallelization. - * \param first The beginning of the input range. - * \param last The end of the input range. - * \param result The beginning of the output range. - * \return The iterator result + (last - first) - * - * \tparam DerivedPolicy The name of the derived execution policy. - * \tparam InputIterator is a model of Input Iterator, - * and \c x and \c y are objects of \p InputIterator's \c value_type, then \c x - \c is defined, - * and \p InputIterator's \c value_type is convertible to a type in \p OutputIterator's set of \c value_types, - * and the return type of x - y is convertible to a type in \p OutputIterator's set of \c value_types. - * \tparam OutputIterator is a model of Output Iterator. - * - * \remark Note that \p result is permitted to be the same iterator as \p first. This is - * useful for computing differences "in place". - * - * The following code snippet demonstrates how to use \p adjacent_difference to compute - * the difference between adjacent elements of a range using the \p thrust::device execution policy: - * - * \code - * #include - * #include - * #include - * ... - * int h_data[8] = {1, 2, 1, 2, 1, 2, 1, 2}; - * thrust::device_vector d_data(h_data, h_data + 8); - * thrust::device_vector d_result(8); - * - * thrust::adjacent_difference(thrust::device, d_data.begin(), d_data.end(), d_result.begin()); - * - * // d_result is now [1, 1, -1, 1, -1, 1, -1, 1] - * \endcode - * - * \see https://en.cppreference.com/w/cpp/algorithm/adjacent_difference - * \see inclusive_scan - */ -template -__host__ __device__ -OutputIterator adjacent_difference(const thrust::detail::execution_policy_base &exec, - InputIterator first, InputIterator last, - OutputIterator result); - -/*! \p adjacent_difference calculates the differences of adjacent elements in the - * range [first, last). That is, *first is assigned to - * \*result, and, for each iterator \p i in the range - * [first + 1, last), binary_op(\*i, \*(i - 1)) is assigned to - * \*(result + (i - first)). - * - * This version of \p adjacent_difference uses the binary function \p binary_op to - * calculate differences. - * - * The algorithm's execution is parallelized as determined by \p exec. - * - * \param exec The execution policy to use for parallelization. - * \param first The beginning of the input range. - * \param last The end of the input range. - * \param result The beginning of the output range. - * \param binary_op The binary function used to compute differences. - * \return The iterator result + (last - first) - * - * \tparam DerivedPolicy The name of the derived execution policy. - * \tparam InputIterator is a model of Input Iterator, - * and \p InputIterator's \c value_type is convertible to \p BinaryFunction's \c first_argument_type and \c second_argument_type, - * and \p InputIterator's \c value_type is convertible to a type in \p OutputIterator's set of \c value_types. - * \tparam OutputIterator is a model of Output Iterator. - * \tparam BinaryFunction's \c result_type is convertible to a type in \p OutputIterator's set of \c value_types. - * - * \remark Note that \p result is permitted to be the same iterator as \p first. This is - * useful for computing differences "in place". - * - * The following code snippet demonstrates how to use \p adjacent_difference to compute - * the sum between adjacent elements of a range using the \p thrust::device execution policy: - * - * \code - * #include - * #include - * #include - * #include - * ... - * int h_data[8] = {1, 2, 1, 2, 1, 2, 1, 2}; - * thrust::device_vector d_data(h_data, h_data + 8); - * thrust::device_vector d_result(8); - * - * thrust::adjacent_difference(thrust::device, d_data.begin(), d_data.end(), d_result.begin(), thrust::plus()); - * - * // d_result is now [1, 3, 3, 3, 3, 3, 3, 3] - * \endcode - * - * \see https://en.cppreference.com/w/cpp/algorithm/adjacent_difference - * \see inclusive_scan - */ -template -__host__ __device__ -OutputIterator adjacent_difference(const thrust::detail::execution_policy_base &exec, - InputIterator first, InputIterator last, - OutputIterator result, - BinaryFunction binary_op); - -/*! \p adjacent_difference calculates the differences of adjacent elements in the - * range [first, last). That is, \*first is assigned to - * \*result, and, for each iterator \p i in the range - * [first + 1, last), the difference of \*i and *(i - 1) - * is assigned to \*(result + (i - first)). - * - * This version of \p adjacent_difference uses operator- to calculate - * differences. - * - * \param first The beginning of the input range. - * \param last The end of the input range. - * \param result The beginning of the output range. - * \return The iterator result + (last - first) - * - * \tparam InputIterator is a model of Input Iterator, - * and \c x and \c y are objects of \p InputIterator's \c value_type, then \c x - \c is defined, - * and \p InputIterator's \c value_type is convertible to a type in \p OutputIterator's set of \c value_types, - * and the return type of x - y is convertible to a type in \p OutputIterator's set of \c value_types. - * \tparam OutputIterator is a model of Output Iterator. - * - * \remark Note that \p result is permitted to be the same iterator as \p first. This is - * useful for computing differences "in place". - * - * The following code snippet demonstrates how to use \p adjacent_difference to compute - * the difference between adjacent elements of a range. - * - * \code - * #include - * #include - * ... - * int h_data[8] = {1, 2, 1, 2, 1, 2, 1, 2}; - * thrust::device_vector d_data(h_data, h_data + 8); - * thrust::device_vector d_result(8); - * - * thrust::adjacent_difference(d_data.begin(), d_data.end(), d_result.begin()); - * - * // d_result is now [1, 1, -1, 1, -1, 1, -1, 1] - * \endcode - * - * \see https://en.cppreference.com/w/cpp/algorithm/adjacent_difference - * \see inclusive_scan - */ -template -OutputIterator adjacent_difference(InputIterator first, InputIterator last, - OutputIterator result); - -/*! \p adjacent_difference calculates the differences of adjacent elements in the - * range [first, last). That is, *first is assigned to - * \*result, and, for each iterator \p i in the range - * [first + 1, last), binary_op(\*i, \*(i - 1)) is assigned to - * \*(result + (i - first)). - * - * This version of \p adjacent_difference uses the binary function \p binary_op to - * calculate differences. - * - * \param first The beginning of the input range. - * \param last The end of the input range. - * \param result The beginning of the output range. - * \param binary_op The binary function used to compute differences. - * \return The iterator result + (last - first) - * - * \tparam InputIterator is a model of Input Iterator, - * and \p InputIterator's \c value_type is convertible to \p BinaryFunction's \c first_argument_type and \c second_argument_type, - * and \p InputIterator's \c value_type is convertible to a type in \p OutputIterator's set of \c value_types. - * \tparam OutputIterator is a model of Output Iterator. - * \tparam BinaryFunction's \c result_type is convertible to a type in \p OutputIterator's set of \c value_types. - * - * \remark Note that \p result is permitted to be the same iterator as \p first. This is - * useful for computing differences "in place". - * - * The following code snippet demonstrates how to use \p adjacent_difference to compute - * the sum between adjacent elements of a range. - * - * \code - * #include - * #include - * #include - * ... - * int h_data[8] = {1, 2, 1, 2, 1, 2, 1, 2}; - * thrust::device_vector d_data(h_data, h_data + 8); - * thrust::device_vector d_result(8); - * - * thrust::adjacent_difference(d_data.begin(), d_data.end(), d_result.begin(), thrust::plus()); - * - * // d_result is now [1, 3, 3, 3, 3, 3, 3, 3] - * \endcode - * - * \see https://en.cppreference.com/w/cpp/algorithm/adjacent_difference - * \see inclusive_scan - */ -template -OutputIterator adjacent_difference(InputIterator first, InputIterator last, - OutputIterator result, - BinaryFunction binary_op); - -/*! \} - */ - -THRUST_NAMESPACE_END - -#include - diff --git a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/thrust/advance.h b/IfcPlusPlus/src/external/manifold/src/third_party/thrust/thrust/advance.h deleted file mode 100644 index a5162e203..000000000 --- a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/thrust/advance.h +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright 2008-2013 NVIDIA Corporation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -/*! \file advance.h - * \brief Advance an iterator by a given distance. - */ - -#pragma once - -#include - -THRUST_NAMESPACE_BEGIN - -/*! \addtogroup iterators - * \{ - */ - -/*! \p advance(i, n) increments the iterator \p i by the distance \p n. - * If n > 0 it is equivalent to executing ++i \p n - * times, and if n < 0 it is equivalent to executing --i - * \p n times. If n == 0, the call has no effect. - * - * \param i The iterator to be advanced. - * \param n The distance by which to advance the iterator. - * - * \tparam InputIterator is a model of Input Iterator. - * \tparam Distance is an integral type that is convertible to \p InputIterator's distance type. - * - * \pre \p n shall be negative only for bidirectional and random access iterators. - * - * The following code snippet demonstrates how to use \p advance to increment - * an iterator a given number of times. - * - * \code - * #include - * #include - * ... - * thrust::device_vector vec(13); - * thrust::device_vector::iterator iter = vec.begin(); - * - * thrust::advance(iter, 7); - * - * // iter - vec.begin() == 7 - * \endcode - * - * \see https://en.cppreference.com/w/cpp/iterator/advance - */ -template -__host__ __device__ -void advance(InputIterator& i, Distance n); - -/*! \p next(i, n) returns the \p n th successor of the iterator \p i. - * - * \param i An iterator. - * \param n The number of elements to advance. - * - * \tparam InputIterator must meet the InputIterator. - * - * \pre \p n shall be negative only for bidirectional and random access iterators. - * - * The following code snippet demonstrates how to use \p next. - * - * \code - * #include - * #include - * ... - * thrust::device_vector vec(13); - * thrust::device_vector::iterator i0 = vec.begin(); - * - * auto i1 = thrust::next(i0); - * - * // i0 - vec.begin() == 0 - * // i1 - vec.begin() == 1 - * \endcode - * - * \see https://en.cppreference.com/w/cpp/iterator/next - */ -#if 0 // Doxygen only -template -__host__ __device__ -InputIterator next( - InputIterator i -, typename iterator_traits::difference_type n = 1 -); -#endif - -/*! \p prev(i, n) returns the \p n th predecessor of the iterator \p i. - * - * \param i An iterator. - * \param n The number of elements to descend. - * - * \tparam BidirectionalIterator must meet the BidirectionalIterator. - * - * The following code snippet demonstrates how to use \p prev. - * - * \code - * #include - * #include - * ... - * thrust::device_vector vec(13); - * thrust::device_vector::iterator i0 = vec.end(); - * - * auto i1 = thrust::prev(i0); - * - * // vec.end() - i0 == 0 - * // vec.end() - i1 == 1 - * \endcode - * - * \see https://en.cppreference.com/w/cpp/iterator/prev - */ -#if 0 // Doxygen only -template -__host__ __device__ -BidirectionalIterator prev( - BidirectionalIterator i -, typename iterator_traits::difference_type n = 1 -); -#endif - -/*! \} // end iterators - */ - -THRUST_NAMESPACE_END - -#include - diff --git a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/thrust/allocate_unique.h b/IfcPlusPlus/src/external/manifold/src/third_party/thrust/thrust/allocate_unique.h deleted file mode 100644 index ff10cb51c..000000000 --- a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/thrust/allocate_unique.h +++ /dev/null @@ -1,443 +0,0 @@ -// Copyright (c) 2018 NVIDIA Corporation -// Author: Bryce Adelstein Lelbach -// -// Distributed under the Boost Software License v1.0 (boost.org/LICENSE_1_0.txt) - -#pragma once - -#include -#include - -#if THRUST_CPP_DIALECT >= 2011 - -#include -#include -#include -#include - -#include -#include - -THRUST_NAMESPACE_BEGIN - -// wg21.link/p0316r0 - -/////////////////////////////////////////////////////////////////////////////// - -namespace detail -{ - -template -void allocator_delete_impl( - Allocator const& alloc, Pointer p, std::false_type -) -{ - using traits = typename detail::allocator_traits< - typename std::remove_cv< - typename std::remove_reference::type - >::type - >; - - typename traits::allocator_type alloc_T(alloc); - - if (nullptr != pointer_traits::get(p)) - { - traits::destroy(alloc_T, thrust::raw_pointer_cast(p)); - traits::deallocate(alloc_T, p, 1); - } -} - -template -void allocator_delete_impl( - Allocator const& alloc, Pointer p, std::true_type -) -{ - using traits = typename detail::allocator_traits< - typename std::remove_cv< - typename std::remove_reference::type - >::type - >; - - typename traits::allocator_type alloc_T(alloc); - - if (nullptr != pointer_traits::get(p)) - { - traits::deallocate(alloc_T, p, 1); - } -} - -} // namespace detail - -template -struct allocator_delete final -{ - using allocator_type - = typename std::remove_cv< - typename std::remove_reference::type - >::type::template rebind::other; - using pointer = typename detail::allocator_traits::pointer; - - template - allocator_delete(UAllocator&& other) noexcept - : alloc_(THRUST_FWD(other)) - {} - - template - allocator_delete( - allocator_delete const& other - ) noexcept - : alloc_(other.get_allocator()) - {} - template - allocator_delete( - allocator_delete&& other - ) noexcept - : alloc_(std::move(other.get_allocator())) - {} - - template - allocator_delete& operator=( - allocator_delete const& other - ) noexcept - { - alloc_ = other.get_allocator(); - return *this; - } - template - allocator_delete& operator=( - allocator_delete&& other - ) noexcept - { - alloc_ = std::move(other.get_allocator()); - return *this; - } - - void operator()(pointer p) - { - std::integral_constant ic; - - detail::allocator_delete_impl(get_allocator(), p, ic); - } - - allocator_type& get_allocator() noexcept { return alloc_; } - allocator_type const& get_allocator() const noexcept { return alloc_; } - - void swap(allocator_delete& other) noexcept - { - using std::swap; - swap(alloc_, other.alloc_); - } - -private: - allocator_type alloc_; -}; - -template -using uninitialized_allocator_delete = allocator_delete; - -namespace detail { - -template -void array_allocator_delete_impl( - Allocator const& alloc, Pointer p, Size count, std::false_type -) -{ - using traits = typename detail::allocator_traits< - typename std::remove_cv< - typename std::remove_reference::type - >::type - >; - - typename traits::allocator_type alloc_T(alloc); - - if (nullptr != pointer_traits::get(p)) - { - destroy_n(alloc_T, p, count); - traits::deallocate(alloc_T, p, count); - } -} - -template -void array_allocator_delete_impl( - Allocator const& alloc, Pointer p, Size count, std::true_type -) -{ - using traits = typename detail::allocator_traits< - typename std::remove_cv< - typename std::remove_reference::type - >::type - >; - - typename traits::allocator_type alloc_T(alloc); - - if (nullptr != pointer_traits::get(p)) - { - traits::deallocate(alloc_T, p, count); - } -} - -} // namespace detail - -template -struct array_allocator_delete final -{ - using allocator_type - = typename std::remove_cv< - typename std::remove_reference::type - >::type::template rebind::other; - using pointer = typename detail::allocator_traits::pointer; - - template - array_allocator_delete(UAllocator&& other, std::size_t n) noexcept - : alloc_(THRUST_FWD(other)), count_(n) - {} - - template - array_allocator_delete( - array_allocator_delete const& other - ) noexcept - : alloc_(other.get_allocator()), count_(other.count_) - {} - template - array_allocator_delete( - array_allocator_delete&& other - ) noexcept - : alloc_(std::move(other.get_allocator())), count_(other.count_) - {} - - template - array_allocator_delete& operator=( - array_allocator_delete const& other - ) noexcept - { - alloc_ = other.get_allocator(); - count_ = other.count_; - return *this; - } - template - array_allocator_delete& operator=( - array_allocator_delete&& other - ) noexcept - { - alloc_ = std::move(other.get_allocator()); - count_ = other.count_; - return *this; - } - - void operator()(pointer p) - { - std::integral_constant ic; - - detail::array_allocator_delete_impl(get_allocator(), p, count_, ic); - } - - allocator_type& get_allocator() noexcept { return alloc_; } - allocator_type const& get_allocator() const noexcept { return alloc_; } - - void swap(array_allocator_delete& other) noexcept - { - using std::swap; - swap(alloc_, other.alloc_); - swap(count_, other.count_); - } - -private: - allocator_type alloc_; - std::size_t count_; -}; - -template -using uninitialized_array_allocator_delete - = array_allocator_delete; - -/////////////////////////////////////////////////////////////////////////////// - -template -struct tagged_deleter : Lambda -{ - __host__ __device__ - tagged_deleter(Lambda&& l) : Lambda(THRUST_FWD(l)) {} - - using pointer = Pointer; -}; - -template -__host__ __device__ -tagged_deleter -make_tagged_deleter(Lambda&& l) -{ - return tagged_deleter(THRUST_FWD(l)); -} - -/////////////////////////////////////////////////////////////////////////////// - -template -__host__ -std::unique_ptr< - T, - allocator_delete< - T - , typename detail::allocator_traits< - typename std::remove_cv< - typename std::remove_reference::type - >::type - >::template rebind_traits::allocator_type - > -> -allocate_unique( - Allocator const& alloc, Args&&... args -) -{ - using traits = typename detail::allocator_traits< - typename std::remove_cv< - typename std::remove_reference::type - >::type - >::template rebind_traits; - - typename traits::allocator_type alloc_T(alloc); - - auto hold_deleter = make_tagged_deleter( - [&alloc_T] (typename traits::pointer p) { - traits::deallocate(alloc_T, p, 1); - } - ); - using hold_t = std::unique_ptr; - auto hold = hold_t(traits::allocate(alloc_T, 1), hold_deleter); - - traits::construct( - alloc_T, thrust::raw_pointer_cast(hold.get()), THRUST_FWD(args)... - ); - auto deleter = allocator_delete(alloc); - return std::unique_ptr - (hold.release(), std::move(deleter)); -} - -template -__host__ -std::unique_ptr< - T, - uninitialized_allocator_delete< - T - , typename detail::allocator_traits< - typename std::remove_cv< - typename std::remove_reference::type - >::type - >::template rebind_traits::allocator_type - > -> -uninitialized_allocate_unique( - Allocator const& alloc -) -{ - using traits = typename detail::allocator_traits< - typename std::remove_cv< - typename std::remove_reference::type - >::type - >::template rebind_traits; - - typename traits::allocator_type alloc_T(alloc); - - auto hold_deleter = make_tagged_deleter( - [&alloc_T] (typename traits::pointer p) { - traits::deallocate(alloc_T, p, 1); - } - ); - using hold_t = std::unique_ptr; - auto hold = hold_t(traits::allocate(alloc_T, 1), hold_deleter); - - auto deleter = uninitialized_allocator_delete< - T, typename traits::allocator_type - >(alloc_T); - return std::unique_ptr - (hold.release(), std::move(deleter)); -} - -template -__host__ -std::unique_ptr< - T[], - array_allocator_delete< - T - , typename detail::allocator_traits< - typename std::remove_cv< - typename std::remove_reference::type - >::type - >::template rebind_traits::allocator_type - > -> -allocate_unique_n( - Allocator const& alloc, Size n, Args&&... args -) -{ - using traits = typename detail::allocator_traits< - typename std::remove_cv< - typename std::remove_reference::type - >::type - >::template rebind_traits; - - typename traits::allocator_type alloc_T(alloc); - - auto hold_deleter = make_tagged_deleter( - [n, &alloc_T] (typename traits::pointer p) { - traits::deallocate(alloc_T, p, n); - } - ); - using hold_t = std::unique_ptr; - auto hold = hold_t(traits::allocate(alloc_T, n), hold_deleter); - - uninitialized_construct_n_with_allocator( - alloc_T, hold.get(), n, THRUST_FWD(args)... - ); - auto deleter = array_allocator_delete< - T, typename traits::allocator_type - >(alloc_T, n); - return std::unique_ptr - (hold.release(), std::move(deleter)); -} - -template -__host__ -std::unique_ptr< - T[], - uninitialized_array_allocator_delete< - T - , typename detail::allocator_traits< - typename std::remove_cv< - typename std::remove_reference::type - >::type - >::template rebind_traits::allocator_type - > -> -uninitialized_allocate_unique_n( - Allocator const& alloc, Size n -) -{ - using traits = typename detail::allocator_traits< - typename std::remove_cv< - typename std::remove_reference::type - >::type - >::template rebind_traits; - - typename traits::allocator_type alloc_T(alloc); - - auto hold_deleter = make_tagged_deleter( - [n, &alloc_T] (typename traits::pointer p) { - traits::deallocate(alloc_T, p, n); - } - ); - using hold_t = std::unique_ptr; - auto hold = hold_t(traits::allocate(alloc_T, n), hold_deleter); - - auto deleter = uninitialized_array_allocator_delete< - T, typename traits::allocator_type - >(alloc_T, n); - return std::unique_ptr - (hold.release(), std::move(deleter)); -} - -/////////////////////////////////////////////////////////////////////////////// - -THRUST_NAMESPACE_END - -#endif // THRUST_CPP_DIALECT >= 2011 - diff --git a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/thrust/async/copy.h b/IfcPlusPlus/src/external/manifold/src/third_party/thrust/thrust/async/copy.h deleted file mode 100644 index a88f46905..000000000 --- a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/thrust/async/copy.h +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright 2008-2018 NVIDIA Corporation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/*! \file async/copy.h - * \brief Functions for asynchronously copying a range. - */ - -#pragma once - -#include -#include - -#if THRUST_CPP_DIALECT >= 2014 - -#include -#include -#include -#include - -#include - -THRUST_NAMESPACE_BEGIN - -namespace async -{ - -namespace unimplemented -{ - -template < - typename FromPolicy, typename ToPolicy -, typename ForwardIt, typename Sentinel, typename OutputIt -> -__host__ -event -async_copy( - thrust::execution_policy& from_exec -, thrust::execution_policy& to_exec -, ForwardIt first, Sentinel last, OutputIt output -) -{ - THRUST_STATIC_ASSERT_MSG( - (thrust::detail::depend_on_instantiation::value) - , "this algorithm is not implemented for the specified system" - ); - return {}; -} - -} // namespace unimplemented - -namespace copy_detail -{ - -using thrust::async::unimplemented::async_copy; - -struct copy_fn final -{ - template < - typename FromPolicy, typename ToPolicy - , typename ForwardIt, typename Sentinel, typename OutputIt - > - __host__ - static auto call( - thrust::detail::execution_policy_base const& from_exec - , thrust::detail::execution_policy_base const& to_exec - , ForwardIt&& first, Sentinel&& last - , OutputIt&& output - ) - // ADL dispatch. - THRUST_RETURNS( - async_copy( - thrust::detail::derived_cast(thrust::detail::strip_const(from_exec)) - , thrust::detail::derived_cast(thrust::detail::strip_const(to_exec)) - , THRUST_FWD(first), THRUST_FWD(last) - , THRUST_FWD(output) - ) - ) - - template < - typename DerivedPolicy - , typename ForwardIt, typename Sentinel, typename OutputIt - > - __host__ - static auto call( - thrust::detail::execution_policy_base const& exec - , ForwardIt&& first, Sentinel&& last - , OutputIt&& output - ) - THRUST_RETURNS( - copy_fn::call( - thrust::detail::derived_cast(thrust::detail::strip_const(exec)) - // Synthesize a suitable new execution policy, because we don't want to - // try and extract twice from the one we were passed. - , typename remove_cvref_t< - decltype(thrust::detail::derived_cast(thrust::detail::strip_const(exec))) - >::tag_type{} - , THRUST_FWD(first), THRUST_FWD(last) - , THRUST_FWD(output) - ) - ) - - template - __host__ - static auto call(ForwardIt&& first, Sentinel&& last, OutputIt&& output) - THRUST_RETURNS( - copy_fn::call( - thrust::detail::select_system( - typename thrust::iterator_system>::type{} - ) - , thrust::detail::select_system( - typename thrust::iterator_system>::type{} - ) - , THRUST_FWD(first), THRUST_FWD(last) - , THRUST_FWD(output) - ) - ) - - template - THRUST_NODISCARD __host__ - auto operator()(Args&&... args) const - THRUST_RETURNS( - call(THRUST_FWD(args)...) - ) -}; - -} // namespace copy_detail - -THRUST_INLINE_CONSTANT copy_detail::copy_fn copy{}; - -} // namespace async - -THRUST_NAMESPACE_END - -#endif - diff --git a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/thrust/async/for_each.h b/IfcPlusPlus/src/external/manifold/src/third_party/thrust/thrust/async/for_each.h deleted file mode 100644 index 6d4c4130a..000000000 --- a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/thrust/async/for_each.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2008-2018 NVIDIA Corporation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a for_each of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/*! \file async/for_each.h - * \brief Functions for asynchronously iterating over the elements of a range. - */ - -#pragma once - -#include -#include - -#if THRUST_CPP_DIALECT >= 2014 - -#include -#include -#include -#include - -#include - -THRUST_NAMESPACE_BEGIN - -namespace async -{ - -namespace unimplemented -{ - -template < - typename DerivedPolicy -, typename ForwardIt, typename Sentinel, typename UnaryFunction -> -__host__ -event -async_for_each( - thrust::execution_policy&, ForwardIt, Sentinel, UnaryFunction -) -{ - THRUST_STATIC_ASSERT_MSG( - (thrust::detail::depend_on_instantiation::value) - , "this algorithm is not implemented for the specified system" - ); - return {}; -} - -} // namespace unimplemented - -namespace for_each_detail -{ - -using thrust::async::unimplemented::async_for_each; - -struct for_each_fn final -{ - template < - typename DerivedPolicy - , typename ForwardIt, typename Sentinel, typename UnaryFunction - > - __host__ - static auto call( - thrust::detail::execution_policy_base const& exec - , ForwardIt&& first, Sentinel&& last - , UnaryFunction&& f - ) - // ADL dispatch. - THRUST_RETURNS( - async_for_each( - thrust::detail::derived_cast(thrust::detail::strip_const(exec)) - , THRUST_FWD(first), THRUST_FWD(last) - , THRUST_FWD(f) - ) - ) - - template - __host__ - static auto call(ForwardIt&& first, Sentinel&& last, UnaryFunction&& f) - THRUST_RETURNS( - for_each_fn::call( - thrust::detail::select_system( - typename iterator_system>::type{} - ) - , THRUST_FWD(first), THRUST_FWD(last) - , THRUST_FWD(f) - ) - ) - - template - THRUST_NODISCARD __host__ - auto operator()(Args&&... args) const - THRUST_RETURNS( - call(THRUST_FWD(args)...) - ) -}; - -} // namespace for_each_detail - -THRUST_INLINE_CONSTANT for_each_detail::for_each_fn for_each{}; - -} // namespace async - -THRUST_NAMESPACE_END - -#endif diff --git a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/thrust/async/reduce.h b/IfcPlusPlus/src/external/manifold/src/third_party/thrust/thrust/async/reduce.h deleted file mode 100644 index 57d955d16..000000000 --- a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/thrust/async/reduce.h +++ /dev/null @@ -1,440 +0,0 @@ -/* - * Copyright 2008-2018 NVIDIA Corporation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/*! \file async/reduce.h - * \brief Functions for asynchronously reducing a range to a single value. - */ - -#pragma once - -#include -#include - -#if THRUST_CPP_DIALECT >= 2014 - -#include -#include -#include -#include -#include -#include - -#include - -THRUST_NAMESPACE_BEGIN - -namespace async -{ - -namespace unimplemented -{ - -template < - typename DerivedPolicy -, typename ForwardIt, typename Sentinel, typename T, typename BinaryOp -> -__host__ -future -async_reduce( - thrust::execution_policy&, ForwardIt, Sentinel, T, BinaryOp -) -{ - THRUST_STATIC_ASSERT_MSG( - (thrust::detail::depend_on_instantiation::value) - , "this algorithm is not implemented for the specified system" - ); - return {}; -} - -} // namespace unimplemented - -namespace reduce_detail -{ - -using thrust::async::unimplemented::async_reduce; - -struct reduce_fn final -{ - template < - typename DerivedPolicy - , typename ForwardIt, typename Sentinel, typename T, typename BinaryOp - > - __host__ - static auto call( - thrust::detail::execution_policy_base const& exec - , ForwardIt&& first, Sentinel&& last - , T&& init - , BinaryOp&& op - ) - // ADL dispatch. - THRUST_RETURNS( - async_reduce( - thrust::detail::derived_cast(thrust::detail::strip_const(exec)) - , THRUST_FWD(first), THRUST_FWD(last) - , THRUST_FWD(init) - , THRUST_FWD(op) - ) - ) - - template < - typename DerivedPolicy - , typename ForwardIt, typename Sentinel, typename T - > - __host__ - static auto call4( - thrust::detail::execution_policy_base const& exec - , ForwardIt&& first, Sentinel&& last - , T&& init - , thrust::true_type - ) - // ADL dispatch. - THRUST_RETURNS( - async_reduce( - thrust::detail::derived_cast(thrust::detail::strip_const(exec)) - , THRUST_FWD(first), THRUST_FWD(last) - , THRUST_FWD(init) - , thrust::plus>{} - ) - ) - - template < - typename DerivedPolicy - , typename ForwardIt, typename Sentinel - > - __host__ - static auto - call3( - thrust::detail::execution_policy_base const& exec - , ForwardIt&& first, Sentinel&& last - , thrust::true_type - ) - // ADL dispatch. - THRUST_RETURNS( - async_reduce( - thrust::detail::derived_cast(thrust::detail::strip_const(exec)) - , THRUST_FWD(first), THRUST_FWD(last) - , typename iterator_traits>::value_type{} - , thrust::plus< - remove_cvref_t< - typename iterator_traits>::value_type - > - >{} - ) - ) - - template - __host__ - static auto call4(ForwardIt&& first, Sentinel&& last, - T&& init, - BinaryOp&& op, - thrust::false_type) - THRUST_RETURNS( - reduce_fn::call( - thrust::detail::select_system( - typename iterator_system>::type{} - ) - , THRUST_FWD(first), THRUST_FWD(last) - , THRUST_FWD(init) - , THRUST_FWD(op) - ) - ) - - template - __host__ - static auto call3(ForwardIt&& first, Sentinel&& last, - T&& init, - thrust::false_type) - THRUST_RETURNS( - reduce_fn::call( - thrust::detail::select_system( - typename iterator_system>::type{} - ) - , THRUST_FWD(first), THRUST_FWD(last) - , THRUST_FWD(init) - , thrust::plus>{} - ) - ) - - // MSVC WAR: MSVC gets angsty and eats all available RAM when we try to detect - // if T1 is an execution_policy by using SFINAE. Switching to a static - // dispatch pattern to prevent this. - template - __host__ - static auto call(T1&& t1, T2&& t2, T3&& t3) - THRUST_RETURNS( - reduce_fn::call3(THRUST_FWD(t1), THRUST_FWD(t2), THRUST_FWD(t3), - thrust::is_execution_policy>{}) - ) - - template - __host__ - static auto call(T1&& t1, T2&& t2, T3&& t3, T4&& t4) - THRUST_RETURNS( - reduce_fn::call4(THRUST_FWD(t1), THRUST_FWD(t2), THRUST_FWD(t3), THRUST_FWD(t4), - thrust::is_execution_policy>{}) - ) - - template - __host__ - static auto call(ForwardIt&& first, Sentinel&& last) - THRUST_RETURNS( - reduce_fn::call( - thrust::detail::select_system( - typename iterator_system>::type{} - ) - , THRUST_FWD(first), THRUST_FWD(last) - , typename iterator_traits>::value_type{} - , thrust::plus< - remove_cvref_t< - typename iterator_traits>::value_type - > - >{} - ) - ) - - template - THRUST_NODISCARD __host__ - auto operator()(Args&&... args) const - THRUST_RETURNS( - call(THRUST_FWD(args)...) - ) -}; - -} // namespace reduce_detail - -THRUST_INLINE_CONSTANT reduce_detail::reduce_fn reduce{}; - -/////////////////////////////////////////////////////////////////////////////// - -namespace unimplemented -{ - -template < - typename DerivedPolicy -, typename ForwardIt, typename Sentinel, typename OutputIt -, typename T, typename BinaryOp -> -__host__ -event -async_reduce_into( - thrust::execution_policy& -, ForwardIt, Sentinel, OutputIt, T, BinaryOp -) -{ - THRUST_STATIC_ASSERT_MSG( - (thrust::detail::depend_on_instantiation::value) - , "this algorithm is not implemented for the specified system" - ); - return {}; -} - -} // namespace unimplemented - -namespace reduce_into_detail -{ - -using thrust::async::unimplemented::async_reduce_into; - -struct reduce_into_fn final -{ - template < - typename DerivedPolicy - , typename ForwardIt, typename Sentinel, typename OutputIt - , typename T, typename BinaryOp - > - __host__ - static auto call( - thrust::detail::execution_policy_base const& exec - , ForwardIt&& first, Sentinel&& last - , OutputIt&& output - , T&& init - , BinaryOp&& op - ) - // ADL dispatch. - THRUST_RETURNS( - async_reduce_into( - thrust::detail::derived_cast(thrust::detail::strip_const(exec)) - , THRUST_FWD(first), THRUST_FWD(last) - , THRUST_FWD(output) - , THRUST_FWD(init) - , THRUST_FWD(op) - ) - ) - - template < - typename DerivedPolicy - , typename ForwardIt, typename Sentinel, typename OutputIt - , typename T - > - __host__ - static auto call5( - thrust::detail::execution_policy_base const& exec - , ForwardIt&& first, Sentinel&& last - , OutputIt&& output - , T&& init - , thrust::true_type - ) - // ADL dispatch. - THRUST_RETURNS( - async_reduce_into( - thrust::detail::derived_cast(thrust::detail::strip_const(exec)) - , THRUST_FWD(first), THRUST_FWD(last) - , THRUST_FWD(output) - , THRUST_FWD(init) - , thrust::plus>{} - ) - ) - - template < - typename DerivedPolicy - , typename ForwardIt, typename Sentinel, typename OutputIt - > - __host__ - static auto - call4( - thrust::detail::execution_policy_base const& exec - , ForwardIt&& first, Sentinel&& last - , OutputIt&& output - , thrust::true_type - ) - // ADL dispatch. - THRUST_RETURNS( - async_reduce_into( - thrust::detail::derived_cast(thrust::detail::strip_const(exec)) - , THRUST_FWD(first), THRUST_FWD(last) - , THRUST_FWD(output) - , typename iterator_traits>::value_type{} - , thrust::plus< - remove_cvref_t< - typename iterator_traits>::value_type - > - >{} - ) - ) - - template < - typename ForwardIt, typename Sentinel, typename OutputIt - , typename T, typename BinaryOp - > - __host__ - static auto call5( - ForwardIt&& first, Sentinel&& last - , OutputIt&& output - , T&& init - , BinaryOp&& op - , thrust::false_type - ) - THRUST_RETURNS( - reduce_into_fn::call( - thrust::detail::select_system( - typename iterator_system>::type{} - , typename iterator_system>::type{} - ) - , THRUST_FWD(first), THRUST_FWD(last) - , THRUST_FWD(output) - , THRUST_FWD(init) - , THRUST_FWD(op) - ) - ) - - template < - typename ForwardIt, typename Sentinel, typename OutputIt - , typename T - > - __host__ - static auto call4( - ForwardIt&& first, Sentinel&& last - , OutputIt&& output - , T&& init - , thrust::false_type - ) - THRUST_RETURNS( - reduce_into_fn::call( - thrust::detail::select_system( - typename iterator_system>::type{} - , typename iterator_system>::type{} - ) - , THRUST_FWD(first), THRUST_FWD(last) - , THRUST_FWD(output) - , THRUST_FWD(init) - , thrust::plus>{} - ) - ) - - template < - typename ForwardIt, typename Sentinel, typename OutputIt - > - __host__ - static auto call( - ForwardIt&& first, Sentinel&& last - , OutputIt&& output - ) - THRUST_RETURNS( - reduce_into_fn::call( - thrust::detail::select_system( - typename iterator_system>::type{} - , typename iterator_system>::type{} - ) - , THRUST_FWD(first), THRUST_FWD(last) - , THRUST_FWD(output) - , typename iterator_traits>::value_type{} - , thrust::plus< - remove_cvref_t< - typename iterator_traits>::value_type - > - >{} - ) - ) - - // MSVC WAR: MSVC gets angsty and eats all available RAM when we try to detect - // if T1 is an execution_policy by using SFINAE. Switching to a static - // dispatch pattern to prevent this. - template - __host__ - static auto call(T1&& t1, T2&& t2, T3&& t3, T4&& t4) - THRUST_RETURNS( - reduce_into_fn::call4( - THRUST_FWD(t1), THRUST_FWD(t2), THRUST_FWD(t3), THRUST_FWD(t4), - thrust::is_execution_policy>{}) - ) - - template - __host__ - static auto call(T1&& t1, T2&& t2, T3&& t3, T4&& t4, T5&& t5) - THRUST_RETURNS( - reduce_into_fn::call5( - THRUST_FWD(t1), THRUST_FWD(t2), THRUST_FWD(t3), THRUST_FWD(t4), - THRUST_FWD(t5), thrust::is_execution_policy>{}) - ) - - template - THRUST_NODISCARD __host__ - auto operator()(Args&&... args) const - THRUST_RETURNS( - call(THRUST_FWD(args)...) - ) -}; - -} // namespace reduce_into_detail - -THRUST_INLINE_CONSTANT reduce_into_detail::reduce_into_fn reduce_into{}; - -} // namespace async - -THRUST_NAMESPACE_END - -#endif - diff --git a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/thrust/async/scan.h b/IfcPlusPlus/src/external/manifold/src/third_party/thrust/thrust/async/scan.h deleted file mode 100644 index 1bcf81257..000000000 --- a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/thrust/async/scan.h +++ /dev/null @@ -1,344 +0,0 @@ -/* - * Copyright 2008-2020 NVIDIA Corporation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/*! \file async/scan.h - * \brief Functions for asynchronously computing prefix scans. - */ - -#pragma once - -#include -#include - -#if THRUST_CPP_DIALECT >= 2014 - -#include -#include -#include - -#include - -#include -#include -#include - -#include - -THRUST_NAMESPACE_BEGIN - -namespace async -{ - -// Fallback implementations used when no overloads are found via ADL: -namespace unimplemented -{ - -template -event -async_inclusive_scan(thrust::execution_policy&, - ForwardIt, - Sentinel, - OutputIt, - BinaryOp) -{ - THRUST_STATIC_ASSERT_MSG( - (thrust::detail::depend_on_instantiation::value), - "this algorithm is not implemented for the specified system" - ); - return {}; -} - -template -event -async_exclusive_scan(thrust::execution_policy&, - ForwardIt, - Sentinel, - OutputIt, - InitialValueType, - BinaryOp) -{ - THRUST_STATIC_ASSERT_MSG( - (thrust::detail::depend_on_instantiation::value), - "this algorithm is not implemented for the specified system" - ); - return {}; -} - -} // namespace unimplemented - -namespace inclusive_scan_detail -{ - -// Include fallback implementation for ADL failures -using thrust::async::unimplemented::async_inclusive_scan; - -// Implementation of the thrust::async::inclusive_scan CPO. -struct inclusive_scan_fn final -{ - template - auto - operator()(thrust::detail::execution_policy_base const& exec, - ForwardIt&& first, - Sentinel&& last, - OutputIt&& out, - BinaryOp&& op) const - // ADL dispatch. - THRUST_RETURNS( - async_inclusive_scan( - thrust::detail::derived_cast(thrust::detail::strip_const(exec)), - THRUST_FWD(first), - THRUST_FWD(last), - THRUST_FWD(out), - THRUST_FWD(op) - ) - ) - - template - auto - operator()(thrust::detail::execution_policy_base const& exec, - ForwardIt&& first, - Sentinel&& last, - OutputIt&& out) const - // ADL dispatch. - THRUST_RETURNS( - async_inclusive_scan( - thrust::detail::derived_cast(thrust::detail::strip_const(exec)), - THRUST_FWD(first), - THRUST_FWD(last), - THRUST_FWD(out), - thrust::plus<>{} - ) - ) - - template >>> - auto operator()(ForwardIt&& first, - Sentinel&& last, - OutputIt&& out, - BinaryOp&& op) const - // ADL dispatch. - THRUST_RETURNS( - async_inclusive_scan( - thrust::detail::select_system( - iterator_system_t>{}, - iterator_system_t>{} - ), - THRUST_FWD(first), - THRUST_FWD(last), - THRUST_FWD(out), - THRUST_FWD(op) - ) - ) - - template - auto operator()(ForwardIt&& first, Sentinel&& last, OutputIt&& out) const - // ADL dispatch. - THRUST_RETURNS( - async_inclusive_scan( - thrust::detail::select_system( - iterator_system_t>{}, - iterator_system_t>{} - ), - THRUST_FWD(first), - THRUST_FWD(last), - THRUST_FWD(out), - thrust::plus<>{} - ) - ) -}; - -} // namespace inclusive_scan_detail - -THRUST_INLINE_CONSTANT inclusive_scan_detail::inclusive_scan_fn inclusive_scan{}; - -namespace exclusive_scan_detail -{ - -// Include fallback implementation for ADL failures -using thrust::async::unimplemented::async_exclusive_scan; - -// Implementation of the thrust::async::exclusive_scan CPO. -struct exclusive_scan_fn final -{ - template - auto - operator()(thrust::detail::execution_policy_base const& exec, - ForwardIt&& first, - Sentinel&& last, - OutputIt&& out, - InitialValueType&& init, - BinaryOp&& op) const - // ADL dispatch. - THRUST_RETURNS( - async_exclusive_scan( - thrust::detail::derived_cast(thrust::detail::strip_const(exec)), - THRUST_FWD(first), - THRUST_FWD(last), - THRUST_FWD(out), - THRUST_FWD(init), - THRUST_FWD(op) - ) - ) - - template - auto - operator()(thrust::detail::execution_policy_base const& exec, - ForwardIt&& first, - Sentinel&& last, - OutputIt&& out, - InitialValueType&& init) const - // ADL dispatch. - THRUST_RETURNS( - async_exclusive_scan( - thrust::detail::derived_cast(thrust::detail::strip_const(exec)), - THRUST_FWD(first), - THRUST_FWD(last), - THRUST_FWD(out), - THRUST_FWD(init), - thrust::plus<>{} - ) - ) - - template - auto - operator()(thrust::detail::execution_policy_base const& exec, - ForwardIt&& first, - Sentinel&& last, - OutputIt&& out) const - // ADL dispatch. - THRUST_RETURNS( - async_exclusive_scan( - thrust::detail::derived_cast(thrust::detail::strip_const(exec)), - THRUST_FWD(first), - THRUST_FWD(last), - THRUST_FWD(out), - iterator_value_t>{}, - thrust::plus<>{} - ) - ) - - template >>> - auto - operator()(ForwardIt&& first, - Sentinel&& last, - OutputIt&& out, - InitialValueType&& init, - BinaryOp&& op) const - // ADL dispatch. - THRUST_RETURNS( - async_exclusive_scan( - thrust::detail::select_system( - iterator_system_t>{}, - iterator_system_t>{} - ), - THRUST_FWD(first), - THRUST_FWD(last), - THRUST_FWD(out), - THRUST_FWD(init), - THRUST_FWD(op) - ) - ) - - template >>> - auto - operator()(ForwardIt&& first, - Sentinel&& last, - OutputIt&& out, - InitialValueType&& init) const - // ADL dispatch. - THRUST_RETURNS( - async_exclusive_scan( - thrust::detail::select_system( - iterator_system_t>{}, - iterator_system_t>{} - ), - THRUST_FWD(first), - THRUST_FWD(last), - THRUST_FWD(out), - THRUST_FWD(init), - thrust::plus<>{} - ) - ) - - template - auto operator()(ForwardIt&& first, - Sentinel&& last, - OutputIt&& out) const - // ADL dispatch. - THRUST_RETURNS( - async_exclusive_scan( - thrust::detail::select_system( - iterator_system_t>{}, - iterator_system_t>{} - ), - THRUST_FWD(first), - THRUST_FWD(last), - THRUST_FWD(out), - iterator_value_t>{}, - thrust::plus<>{} - ) - ) -}; - -} // namespace exclusive_scan_detail - -THRUST_INLINE_CONSTANT exclusive_scan_detail::exclusive_scan_fn exclusive_scan{}; - -} // namespace async - -THRUST_NAMESPACE_END - -#endif diff --git a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/thrust/async/sort.h b/IfcPlusPlus/src/external/manifold/src/third_party/thrust/thrust/async/sort.h deleted file mode 100644 index 2820f75bd..000000000 --- a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/thrust/async/sort.h +++ /dev/null @@ -1,274 +0,0 @@ -/* - * Copyright 2008-2018 NVIDIA Corporation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/*! \file async/sort.h - * \brief Functions for asynchronously sorting a range. - */ - -#pragma once - -#include -#include - -#if THRUST_CPP_DIALECT >= 2014 - -#include -#include -#include -#include -#include -#include - -#include - -THRUST_NAMESPACE_BEGIN - -namespace async -{ - -namespace unimplemented -{ - -template < - typename DerivedPolicy -, typename ForwardIt, typename Sentinel, typename StrictWeakOrdering -> -__host__ -event -async_stable_sort( - thrust::execution_policy& -, ForwardIt, Sentinel, StrictWeakOrdering -) -{ - THRUST_STATIC_ASSERT_MSG( - (thrust::detail::depend_on_instantiation::value) - , "this algorithm is not implemented for the specified system" - ); - return {}; -} - -} // namespace unimplemented - -namespace stable_sort_detail -{ - -using thrust::async::unimplemented::async_stable_sort; - -struct stable_sort_fn final -{ - template < - typename DerivedPolicy - , typename ForwardIt, typename Sentinel, typename StrictWeakOrdering - > - __host__ - static auto call( - thrust::detail::execution_policy_base const& exec - , ForwardIt&& first, Sentinel&& last - , StrictWeakOrdering&& comp - ) - // ADL dispatch. - THRUST_RETURNS( - async_stable_sort( - thrust::detail::derived_cast(thrust::detail::strip_const(exec)) - , THRUST_FWD(first), THRUST_FWD(last) - , THRUST_FWD(comp) - ) - ) - - template < - typename DerivedPolicy - , typename ForwardIt, typename Sentinel - > - __host__ - static auto call( - thrust::detail::execution_policy_base const& exec - , ForwardIt&& first, Sentinel&& last - ) - // ADL dispatch. - THRUST_RETURNS( - async_stable_sort( - thrust::detail::derived_cast(thrust::detail::strip_const(exec)) - , THRUST_FWD(first), THRUST_FWD(last) - , thrust::less< - typename iterator_traits>::value_type - >{} - ) - ) - - template - __host__ - static auto call(ForwardIt&& first, Sentinel&& last, StrictWeakOrdering&& comp) - THRUST_RETURNS( - stable_sort_fn::call( - thrust::detail::select_system( - typename iterator_system>::type{} - ) - , THRUST_FWD(first), THRUST_FWD(last) - , THRUST_FWD(comp) - ) - ) - - template - __host__ - static auto call(ForwardIt&& first, Sentinel&& last) - THRUST_RETURNS( - stable_sort_fn::call( - THRUST_FWD(first), THRUST_FWD(last) - , thrust::less< - typename iterator_traits>::value_type - >{} - ) - ) - - template - THRUST_NODISCARD __host__ - auto operator()(Args&&... args) const - THRUST_RETURNS( - call(THRUST_FWD(args)...) - ) -}; - -} // namespace stable_sort_detail - -THRUST_INLINE_CONSTANT stable_sort_detail::stable_sort_fn stable_sort{}; - -namespace fallback -{ - -template < - typename DerivedPolicy -, typename ForwardIt, typename Sentinel, typename StrictWeakOrdering -> -__host__ -event -async_sort( - thrust::execution_policy& exec -, ForwardIt&& first, Sentinel&& last, StrictWeakOrdering&& comp -) -{ - return async_stable_sort( - thrust::detail::derived_cast(exec) - , THRUST_FWD(first), THRUST_FWD(last), THRUST_FWD(comp) - ); -} - -} // namespace fallback - -namespace sort_detail -{ - -using thrust::async::fallback::async_sort; - -struct sort_fn final -{ - template < - typename DerivedPolicy - , typename ForwardIt, typename Sentinel, typename StrictWeakOrdering - > - __host__ - static auto call( - thrust::detail::execution_policy_base const& exec - , ForwardIt&& first, Sentinel&& last - , StrictWeakOrdering&& comp - ) - // ADL dispatch. - THRUST_RETURNS( - async_sort( - thrust::detail::derived_cast(thrust::detail::strip_const(exec)) - , THRUST_FWD(first), THRUST_FWD(last) - , THRUST_FWD(comp) - ) - ) - - template < - typename DerivedPolicy - , typename ForwardIt, typename Sentinel - > - __host__ - static auto call3( - thrust::detail::execution_policy_base const& exec - , ForwardIt&& first, Sentinel&& last - , thrust::true_type - ) - THRUST_RETURNS( - sort_fn::call( - exec - , THRUST_FWD(first), THRUST_FWD(last) - , thrust::less< - typename iterator_traits>::value_type - >{} - ) - ) - - template - __host__ - static auto call3(ForwardIt&& first, Sentinel&& last, - StrictWeakOrdering&& comp, - thrust::false_type) - THRUST_RETURNS( - sort_fn::call( - thrust::detail::select_system( - typename iterator_system>::type{} - ) - , THRUST_FWD(first), THRUST_FWD(last) - , THRUST_FWD(comp) - ) - ) - - // MSVC WAR: MSVC gets angsty and eats all available RAM when we try to detect - // if T1 is an execution_policy by using SFINAE. Switching to a static - // dispatch pattern to prevent this. - template - __host__ - static auto call(T1&& t1, T2&& t2, T3&& t3) - THRUST_RETURNS( - sort_fn::call3(THRUST_FWD(t1), THRUST_FWD(t2), THRUST_FWD(t3), - thrust::is_execution_policy>{}) - ) - - template - __host__ - static auto call(ForwardIt&& first, Sentinel&& last) - THRUST_RETURNS( - sort_fn::call( - thrust::detail::select_system( - typename iterator_system>::type{} - ) - , THRUST_FWD(first), THRUST_FWD(last) - , thrust::less< - typename iterator_traits>::value_type - >{} - ) - ) - - template - THRUST_NODISCARD __host__ - auto operator()(Args&&... args) const - THRUST_RETURNS( - call(THRUST_FWD(args)...) - ) -}; - -} // namespace sort_detail - -THRUST_INLINE_CONSTANT sort_detail::sort_fn sort{}; - -} // namespace async - -THRUST_NAMESPACE_END - -#endif - diff --git a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/thrust/async/transform.h b/IfcPlusPlus/src/external/manifold/src/third_party/thrust/thrust/async/transform.h deleted file mode 100644 index 59ea32661..000000000 --- a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/thrust/async/transform.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright 2008-2018 NVIDIA Corporation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a transform of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/*! \file async/transform.h - * \brief Functions for asynchronously transforming a range. - */ - -#pragma once - -#include -#include - -#if THRUST_CPP_DIALECT >= 2014 - -#include -#include -#include -#include - -#include - -THRUST_NAMESPACE_BEGIN - -namespace async -{ - -namespace unimplemented -{ - -template < - typename DerivedPolicy -, typename ForwardIt, typename Sentinel, typename OutputIt -, typename UnaryOperation -> -__host__ -event -async_transform( - thrust::execution_policy& exec -, ForwardIt first, Sentinel last, OutputIt output, UnaryOperation op -) -{ - THRUST_STATIC_ASSERT_MSG( - (thrust::detail::depend_on_instantiation::value) - , "this algorithm is not implemented for the specified system" - ); - return {}; -} - -} // namespace unimplemented - -namespace transform_detail -{ - -using thrust::async::unimplemented::async_transform; - -struct transform_fn final -{ - template < - typename DerivedPolicy - , typename ForwardIt, typename Sentinel, typename OutputIt - , typename UnaryOperation - > - __host__ - static auto - call( - thrust::detail::execution_policy_base const& exec - , ForwardIt&& first, Sentinel&& last - , OutputIt&& output - , UnaryOperation&& op - ) - // ADL dispatch. - THRUST_RETURNS( - async_transform( - thrust::detail::derived_cast(thrust::detail::strip_const(exec)) - , THRUST_FWD(first), THRUST_FWD(last) - , THRUST_FWD(output) - , THRUST_FWD(op) - ) - ) - - template < - typename ForwardIt, typename Sentinel, typename OutputIt - , typename UnaryOperation - > - __host__ - static auto call( - ForwardIt&& first, Sentinel&& last - , OutputIt&& output - , UnaryOperation&& op - ) - THRUST_RETURNS( - transform_fn::call( - thrust::detail::select_system( - typename iterator_system>::type{} - , typename iterator_system>::type{} - ) - , THRUST_FWD(first), THRUST_FWD(last) - , THRUST_FWD(output) - , THRUST_FWD(op) - ) - ) - - template - THRUST_NODISCARD __host__ - auto operator()(Args&&... args) const - THRUST_RETURNS( - call(THRUST_FWD(args)...) - ) -}; - -} // namespace tranform_detail - -THRUST_INLINE_CONSTANT transform_detail::transform_fn transform{}; - -} // namespace async - -THRUST_NAMESPACE_END - -#endif diff --git a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/thrust/binary_search.h b/IfcPlusPlus/src/external/manifold/src/third_party/thrust/thrust/binary_search.h deleted file mode 100644 index 7a4746e0b..000000000 --- a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/thrust/binary_search.h +++ /dev/null @@ -1,1899 +0,0 @@ -/* - * Copyright 2008-2013 NVIDIA Corporation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -/*! \file binary_search.h - * \brief Search for values in sorted ranges. - */ - -#pragma once - -#include -#include -#include - -THRUST_NAMESPACE_BEGIN - -/*! \addtogroup algorithms - */ - - -/*! \addtogroup searching - * \ingroup algorithms - * \{ - */ - - -/*! \addtogroup binary_search Binary Search - * \ingroup searching - * \{ - */ - - -////////////////////// -// Scalar Functions // -////////////////////// - - -/*! \p lower_bound is a version of binary search: it attempts to find - * the element value in an ordered range [first, last). - * Specifically, it returns the first position where value could be - * inserted without violating the ordering. This version of - * \p lower_bound uses operator< for comparison and returns - * the furthermost iterator \c i in [first, last) such that, - * for every iterator \c j in [first, i), *j < value. - * - * The algorithm's execution is parallelized as determined by \p exec. - * - * \param exec The execution policy to use for parallelization. - * \param first The beginning of the ordered sequence. - * \param last The end of the ordered sequence. - * \param value The value to be searched. - * \return The furthermost iterator \c i, such that *i < value. - * - * \tparam DerivedPolicy The name of the derived execution policy. - * \tparam ForwardIterator is a model of Forward Iterator. - * \tparam LessThanComparable is a model of LessThanComparable. - * - * The following code snippet demonstrates how to use \p lower_bound - * to search for values in a ordered range using the \p thrust::device execution policy for parallelization: - * - * \code - * #include - * #include - * #include - * ... - * thrust::device_vector input(5); - * - * input[0] = 0; - * input[1] = 2; - * input[2] = 5; - * input[3] = 7; - * input[4] = 8; - * - * thrust::lower_bound(thrust::device, input.begin(), input.end(), 0); // returns input.begin() - * thrust::lower_bound(thrust::device, input.begin(), input.end(), 1); // returns input.begin() + 1 - * thrust::lower_bound(thrust::device, input.begin(), input.end(), 2); // returns input.begin() + 1 - * thrust::lower_bound(thrust::device, input.begin(), input.end(), 3); // returns input.begin() + 2 - * thrust::lower_bound(thrust::device, input.begin(), input.end(), 8); // returns input.begin() + 4 - * thrust::lower_bound(thrust::device, input.begin(), input.end(), 9); // returns input.end() - * \endcode - * - * \see https://en.cppreference.com/w/cpp/algorithm/lower_bound - * \see \p upper_bound - * \see \p equal_range - * \see \p binary_search - */ -template -__host__ __device__ -ForwardIterator lower_bound(const thrust::detail::execution_policy_base &exec, - ForwardIterator first, - ForwardIterator last, - const LessThanComparable &value); - - -/*! \p lower_bound is a version of binary search: it attempts to find - * the element value in an ordered range [first, last). - * Specifically, it returns the first position where value could be - * inserted without violating the ordering. This version of - * \p lower_bound uses operator< for comparison and returns - * the furthermost iterator \c i in [first, last) such that, - * for every iterator \c j in [first, i), *j < value. - * - * \param first The beginning of the ordered sequence. - * \param last The end of the ordered sequence. - * \param value The value to be searched. - * \return The furthermost iterator \c i, such that *i < value. - * - * \tparam ForwardIterator is a model of Forward Iterator. - * \tparam LessThanComparable is a model of LessThanComparable. - * - * The following code snippet demonstrates how to use \p lower_bound - * to search for values in a ordered range. - * - * \code - * #include - * #include - * ... - * thrust::device_vector input(5); - * - * input[0] = 0; - * input[1] = 2; - * input[2] = 5; - * input[3] = 7; - * input[4] = 8; - * - * thrust::lower_bound(input.begin(), input.end(), 0); // returns input.begin() - * thrust::lower_bound(input.begin(), input.end(), 1); // returns input.begin() + 1 - * thrust::lower_bound(input.begin(), input.end(), 2); // returns input.begin() + 1 - * thrust::lower_bound(input.begin(), input.end(), 3); // returns input.begin() + 2 - * thrust::lower_bound(input.begin(), input.end(), 8); // returns input.begin() + 4 - * thrust::lower_bound(input.begin(), input.end(), 9); // returns input.end() - * \endcode - * - * \see https://en.cppreference.com/w/cpp/algorithm/lower_bound - * \see \p upper_bound - * \see \p equal_range - * \see \p binary_search - */ -template -ForwardIterator lower_bound(ForwardIterator first, - ForwardIterator last, - const LessThanComparable& value); - - -/*! \p lower_bound is a version of binary search: it attempts to find - * the element value in an ordered range [first, last). - * Specifically, it returns the first position where value could be - * inserted without violating the ordering. This version of - * \p lower_bound uses function object \c comp for comparison - * and returns the furthermost iterator \c i in [first, last) - * such that, for every iterator \c j in [first, i), - * comp(*j, value) is \c true. - * - * The algorithm's execution is parallelized as determined by \p exec. - * - * \param exec The execution policy to use for parallelization. - * \param first The beginning of the ordered sequence. - * \param last The end of the ordered sequence. - * \param value The value to be searched. - * \param comp The comparison operator. - * \return The furthermost iterator \c i, such that comp(*i, value) is \c true. - * - * \tparam DerivedPolicy The name of the derived execution policy. - * \tparam ForwardIterator is a model of Forward Iterator. - * \tparam T is comparable to \p ForwardIterator's \c value_type. - * \tparam StrictWeakOrdering is a model of Strict Weak Ordering. - * - * The following code snippet demonstrates how to use \p lower_bound - * to search for values in a ordered range using the \p thrust::device execution policy for parallelization: - * - * \code - * #include - * #include - * #include - * #include - * ... - * thrust::device_vector input(5); - * - * input[0] = 0; - * input[1] = 2; - * input[2] = 5; - * input[3] = 7; - * input[4] = 8; - * - * thrust::lower_bound(input.begin(), input.end(), 0, thrust::less()); // returns input.begin() - * thrust::lower_bound(input.begin(), input.end(), 1, thrust::less()); // returns input.begin() + 1 - * thrust::lower_bound(input.begin(), input.end(), 2, thrust::less()); // returns input.begin() + 1 - * thrust::lower_bound(input.begin(), input.end(), 3, thrust::less()); // returns input.begin() + 2 - * thrust::lower_bound(input.begin(), input.end(), 8, thrust::less()); // returns input.begin() + 4 - * thrust::lower_bound(input.begin(), input.end(), 9, thrust::less()); // returns input.end() - * \endcode - * - * \see https://en.cppreference.com/w/cpp/algorithm/lower_bound - * \see \p upper_bound - * \see \p equal_range - * \see \p binary_search - */ -template -__host__ __device__ -ForwardIterator lower_bound(const thrust::detail::execution_policy_base &exec, - ForwardIterator first, - ForwardIterator last, - const T &value, - StrictWeakOrdering comp); - - -/*! \p lower_bound is a version of binary search: it attempts to find - * the element value in an ordered range [first, last). - * Specifically, it returns the first position where value could be - * inserted without violating the ordering. This version of - * \p lower_bound uses function object \c comp for comparison - * and returns the furthermost iterator \c i in [first, last) - * such that, for every iterator \c j in [first, i), - * comp(*j, value) is \c true. - * - * \param first The beginning of the ordered sequence. - * \param last The end of the ordered sequence. - * \param value The value to be searched. - * \param comp The comparison operator. - * \return The furthermost iterator \c i, such that comp(*i, value) is \c true. - * - * \tparam ForwardIterator is a model of Forward Iterator. - * \tparam T is comparable to \p ForwardIterator's \c value_type. - * \tparam StrictWeakOrdering is a model of Strict Weak Ordering. - * - * The following code snippet demonstrates how to use \p lower_bound - * to search for values in a ordered range. - * - * \code - * #include - * #include - * #include - * ... - * thrust::device_vector input(5); - * - * input[0] = 0; - * input[1] = 2; - * input[2] = 5; - * input[3] = 7; - * input[4] = 8; - * - * thrust::lower_bound(input.begin(), input.end(), 0, thrust::less()); // returns input.begin() - * thrust::lower_bound(input.begin(), input.end(), 1, thrust::less()); // returns input.begin() + 1 - * thrust::lower_bound(input.begin(), input.end(), 2, thrust::less()); // returns input.begin() + 1 - * thrust::lower_bound(input.begin(), input.end(), 3, thrust::less()); // returns input.begin() + 2 - * thrust::lower_bound(input.begin(), input.end(), 8, thrust::less()); // returns input.begin() + 4 - * thrust::lower_bound(input.begin(), input.end(), 9, thrust::less()); // returns input.end() - * \endcode - * - * \see https://en.cppreference.com/w/cpp/algorithm/lower_bound - * \see \p upper_bound - * \see \p equal_range - * \see \p binary_search - */ -template -ForwardIterator lower_bound(ForwardIterator first, - ForwardIterator last, - const T& value, - StrictWeakOrdering comp); - - -/*! \p upper_bound is a version of binary search: it attempts to find - * the element value in an ordered range [first, last). - * Specifically, it returns the last position where value could be - * inserted without violating the ordering. This version of - * \p upper_bound uses operator< for comparison and returns - * the furthermost iterator \c i in [first, last) such that, - * for every iterator \c j in [first, i), value < *j - * is \c false. - * - * The algorithm's execution is parallelized as determined by \p exec. - * - * \param exec The execution policy to use for parallelization. - * \param first The beginning of the ordered sequence. - * \param last The end of the ordered sequence. - * \param value The value to be searched. - * \return The furthermost iterator \c i, such that value < *i is \c false. - * - * \tparam DerivedPolicy The name of the derived execution policy. - * \tparam ForwardIterator is a model of Forward Iterator. - * \tparam LessThanComparable is a model of LessThanComparable. - * - * The following code snippet demonstrates how to use \p upper_bound - * to search for values in a ordered range using the \p thrust::device execution policy for parallelism: - * - * \code - * #include - * #include - * #include - * ... - * thrust::device_vector input(5); - * - * input[0] = 0; - * input[1] = 2; - * input[2] = 5; - * input[3] = 7; - * input[4] = 8; - * - * thrust::upper_bound(thrust::device, input.begin(), input.end(), 0); // returns input.begin() + 1 - * thrust::upper_bound(thrust::device, input.begin(), input.end(), 1); // returns input.begin() + 1 - * thrust::upper_bound(thrust::device, input.begin(), input.end(), 2); // returns input.begin() + 2 - * thrust::upper_bound(thrust::device, input.begin(), input.end(), 3); // returns input.begin() + 2 - * thrust::upper_bound(thrust::device, input.begin(), input.end(), 8); // returns input.end() - * thrust::upper_bound(thrust::device, input.begin(), input.end(), 9); // returns input.end() - * \endcode - * - * \see https://en.cppreference.com/w/cpp/algorithm/upper_bound - * \see \p lower_bound - * \see \p equal_range - * \see \p binary_search - */ -template -__host__ __device__ -ForwardIterator upper_bound(const thrust::detail::execution_policy_base &exec, - ForwardIterator first, - ForwardIterator last, - const LessThanComparable &value); - - -/*! \p upper_bound is a version of binary search: it attempts to find - * the element value in an ordered range [first, last). - * Specifically, it returns the last position where value could be - * inserted without violating the ordering. This version of - * \p upper_bound uses operator< for comparison and returns - * the furthermost iterator \c i in [first, last) such that, - * for every iterator \c j in [first, i), value < *j - * is \c false. - * - * \param first The beginning of the ordered sequence. - * \param last The end of the ordered sequence. - * \param value The value to be searched. - * \return The furthermost iterator \c i, such that value < *i is \c false. - * - * \tparam ForwardIterator is a model of Forward Iterator. - * \tparam LessThanComparable is a model of LessThanComparable. - * - * The following code snippet demonstrates how to use \p upper_bound - * to search for values in a ordered range. - * - * \code - * #include - * #include - * ... - * thrust::device_vector input(5); - * - * input[0] = 0; - * input[1] = 2; - * input[2] = 5; - * input[3] = 7; - * input[4] = 8; - * - * thrust::upper_bound(input.begin(), input.end(), 0); // returns input.begin() + 1 - * thrust::upper_bound(input.begin(), input.end(), 1); // returns input.begin() + 1 - * thrust::upper_bound(input.begin(), input.end(), 2); // returns input.begin() + 2 - * thrust::upper_bound(input.begin(), input.end(), 3); // returns input.begin() + 2 - * thrust::upper_bound(input.begin(), input.end(), 8); // returns input.end() - * thrust::upper_bound(input.begin(), input.end(), 9); // returns input.end() - * \endcode - * - * \see https://en.cppreference.com/w/cpp/algorithm/upper_bound - * \see \p lower_bound - * \see \p equal_range - * \see \p binary_search - */ -template -ForwardIterator upper_bound(ForwardIterator first, - ForwardIterator last, - const LessThanComparable& value); - - -/*! \p upper_bound is a version of binary search: it attempts to find - * the element value in an ordered range [first, last). - * Specifically, it returns the last position where value could be - * inserted without violating the ordering. This version of - * \p upper_bound uses function object \c comp for comparison and returns - * the furthermost iterator \c i in [first, last) such that, - * for every iterator \c j in [first, i), comp(value, *j) - * is \c false. - * - * The algorithm's execution is parallelized as determined by \p exec. - * - * \param exec The execution policy to use for parallelization. - * \param first The beginning of the ordered sequence. - * \param last The end of the ordered sequence. - * \param value The value to be searched. - * \param comp The comparison operator. - * \return The furthermost iterator \c i, such that comp(value, *i) is \c false. - * - * \tparam DerivedPolicy The name of the derived execution policy. - * \tparam ForwardIterator is a model of Forward Iterator. - * \tparam T is comparable to \p ForwardIterator's \c value_type. - * \tparam StrictWeakOrdering is a model of Strict Weak Ordering. - * - * The following code snippet demonstrates how to use \p upper_bound - * to search for values in a ordered range using the \p thrust::device execution policy for parallelization: - * - * \code - * #include - * #include - * #include - * #include - * ... - * thrust::device_vector input(5); - * - * input[0] = 0; - * input[1] = 2; - * input[2] = 5; - * input[3] = 7; - * input[4] = 8; - * - * thrust::upper_bound(thrust::device, input.begin(), input.end(), 0, thrust::less()); // returns input.begin() + 1 - * thrust::upper_bound(thrust::device, input.begin(), input.end(), 1, thrust::less()); // returns input.begin() + 1 - * thrust::upper_bound(thrust::device, input.begin(), input.end(), 2, thrust::less()); // returns input.begin() + 2 - * thrust::upper_bound(thrust::device, input.begin(), input.end(), 3, thrust::less()); // returns input.begin() + 2 - * thrust::upper_bound(thrust::device, input.begin(), input.end(), 8, thrust::less()); // returns input.end() - * thrust::upper_bound(thrust::device, input.begin(), input.end(), 9, thrust::less()); // returns input.end() - * \endcode - * - * \see https://en.cppreference.com/w/cpp/algorithm/upper_bound - * \see \p lower_bound - * \see \p equal_range - * \see \p binary_search - */ -template -__host__ __device__ -ForwardIterator upper_bound(const thrust::detail::execution_policy_base &exec, - ForwardIterator first, - ForwardIterator last, - const T &value, - StrictWeakOrdering comp); - -/*! \p upper_bound is a version of binary search: it attempts to find - * the element value in an ordered range [first, last). - * Specifically, it returns the last position where value could be - * inserted without violating the ordering. This version of - * \p upper_bound uses function object \c comp for comparison and returns - * the furthermost iterator \c i in [first, last) such that, - * for every iterator \c j in [first, i), comp(value, *j) - * is \c false. - * - * \param first The beginning of the ordered sequence. - * \param last The end of the ordered sequence. - * \param value The value to be searched. - * \param comp The comparison operator. - * \return The furthermost iterator \c i, such that comp(value, *i) is \c false. - * - * \tparam ForwardIterator is a model of Forward Iterator. - * \tparam T is comparable to \p ForwardIterator's \c value_type. - * \tparam StrictWeakOrdering is a model of Strict Weak Ordering. - * - * The following code snippet demonstrates how to use \p upper_bound - * to search for values in a ordered range. - * - * \code - * #include - * #include - * #include - * ... - * thrust::device_vector input(5); - * - * input[0] = 0; - * input[1] = 2; - * input[2] = 5; - * input[3] = 7; - * input[4] = 8; - * - * thrust::upper_bound(input.begin(), input.end(), 0, thrust::less()); // returns input.begin() + 1 - * thrust::upper_bound(input.begin(), input.end(), 1, thrust::less()); // returns input.begin() + 1 - * thrust::upper_bound(input.begin(), input.end(), 2, thrust::less()); // returns input.begin() + 2 - * thrust::upper_bound(input.begin(), input.end(), 3, thrust::less()); // returns input.begin() + 2 - * thrust::upper_bound(input.begin(), input.end(), 8, thrust::less()); // returns input.end() - * thrust::upper_bound(input.begin(), input.end(), 9, thrust::less()); // returns input.end() - * \endcode - * - * \see https://en.cppreference.com/w/cpp/algorithm/upper_bound - * \see \p lower_bound - * \see \p equal_range - * \see \p binary_search - */ -template -ForwardIterator upper_bound(ForwardIterator first, - ForwardIterator last, - const T& value, - StrictWeakOrdering comp); - - -/*! \p binary_search is a version of binary search: it attempts to find - * the element value in an ordered range [first, last). - * It returns \c true if an element that is equivalent to \c value - * is present in [first, last) and \c false if no such element - * exists. Specifically, this version returns \c true if and only if - * there exists an iterator \c i in [first, last) such that - * *i < value and value < *i are both \c false. - * - * The algorithm's execution is parallelized as determined by \p exec. - * - * \param exec The execution policy to use for parallelization. - * \param first The beginning of the ordered sequence. - * \param last The end of the ordered sequence. - * \param value The value to be searched. - * \return \c true if an equivalent element exists in [first, last), otherwise \c false. - * - * \tparam DerivedPolicy The name of the derived execution policy. - * \tparam ForwardIterator is a model of Forward Iterator. - * \tparam LessThanComparable is a model of LessThanComparable. - * - * The following code snippet demonstrates how to use \p binary_search - * to search for values in a ordered range using the \p thrust::device execution policy for parallelization: - * - * \code - * #include - * #include - * #include - * ... - * thrust::device_vector input(5); - * - * input[0] = 0; - * input[1] = 2; - * input[2] = 5; - * input[3] = 7; - * input[4] = 8; - * - * thrust::binary_search(thrust::device, input.begin(), input.end(), 0); // returns true - * thrust::binary_search(thrust::device, input.begin(), input.end(), 1); // returns false - * thrust::binary_search(thrust::device, input.begin(), input.end(), 2); // returns true - * thrust::binary_search(thrust::device, input.begin(), input.end(), 3); // returns false - * thrust::binary_search(thrust::device, input.begin(), input.end(), 8); // returns true - * thrust::binary_search(thrust::device, input.begin(), input.end(), 9); // returns false - * \endcode - * - * \see https://en.cppreference.com/w/cpp/algorithm/binary_search - * \see \p lower_bound - * \see \p upper_bound - * \see \p equal_range - */ -template -__host__ __device__ -bool binary_search(const thrust::detail::execution_policy_base &exec, - ForwardIterator first, - ForwardIterator last, - const LessThanComparable& value); - - -/*! \p binary_search is a version of binary search: it attempts to find - * the element value in an ordered range [first, last). - * It returns \c true if an element that is equivalent to \c value - * is present in [first, last) and \c false if no such element - * exists. Specifically, this version returns \c true if and only if - * there exists an iterator \c i in [first, last) such that - * *i < value and value < *i are both \c false. - * - * \param first The beginning of the ordered sequence. - * \param last The end of the ordered sequence. - * \param value The value to be searched. - * \return \c true if an equivalent element exists in [first, last), otherwise \c false. - * - * \tparam ForwardIterator is a model of Forward Iterator. - * \tparam LessThanComparable is a model of LessThanComparable. - * - * The following code snippet demonstrates how to use \p binary_search - * to search for values in a ordered range. - * - * \code - * #include - * #include - * ... - * thrust::device_vector input(5); - * - * input[0] = 0; - * input[1] = 2; - * input[2] = 5; - * input[3] = 7; - * input[4] = 8; - * - * thrust::binary_search(input.begin(), input.end(), 0); // returns true - * thrust::binary_search(input.begin(), input.end(), 1); // returns false - * thrust::binary_search(input.begin(), input.end(), 2); // returns true - * thrust::binary_search(input.begin(), input.end(), 3); // returns false - * thrust::binary_search(input.begin(), input.end(), 8); // returns true - * thrust::binary_search(input.begin(), input.end(), 9); // returns false - * \endcode - * - * \see https://en.cppreference.com/w/cpp/algorithm/binary_search - * \see \p lower_bound - * \see \p upper_bound - * \see \p equal_range - */ -template -bool binary_search(ForwardIterator first, - ForwardIterator last, - const LessThanComparable& value); - - -/*! \p binary_search is a version of binary search: it attempts to find - * the element value in an ordered range [first, last). - * It returns \c true if an element that is equivalent to \c value - * is present in [first, last) and \c false if no such element - * exists. Specifically, this version returns \c true if and only if - * there exists an iterator \c i in [first, last) such that - * comp(*i, value) and comp(value, *i) are both \c false. - * - * The algorithm's execution is parallelized as determined by \p exec. - * - * \param exec The execution policy to use for parallelization. - * \param first The beginning of the ordered sequence. - * \param last The end of the ordered sequence. - * \param value The value to be searched. - * \param comp The comparison operator. - * \return \c true if an equivalent element exists in [first, last), otherwise \c false. - * - * \tparam DerivedPolicy The name of the derived execution policy. - * \tparam ForwardIterator is a model of Forward Iterator. - * \tparam T is comparable to \p ForwardIterator's \c value_type. - * \tparam StrictWeakOrdering is a model of Strict Weak Ordering. - * - * The following code snippet demonstrates how to use \p binary_search - * to search for values in a ordered range using the \p thrust::device execution policy for parallelization: - * - * \code - * #include - * #include - * #include - * #include - * ... - * thrust::device_vector input(5); - * - * input[0] = 0; - * input[1] = 2; - * input[2] = 5; - * input[3] = 7; - * input[4] = 8; - * - * thrust::binary_search(thrust::device, input.begin(), input.end(), 0, thrust::less()); // returns true - * thrust::binary_search(thrust::device, input.begin(), input.end(), 1, thrust::less()); // returns false - * thrust::binary_search(thrust::device, input.begin(), input.end(), 2, thrust::less()); // returns true - * thrust::binary_search(thrust::device, input.begin(), input.end(), 3, thrust::less()); // returns false - * thrust::binary_search(thrust::device, input.begin(), input.end(), 8, thrust::less()); // returns true - * thrust::binary_search(thrust::device, input.begin(), input.end(), 9, thrust::less()); // returns false - * \endcode - * - * \see https://en.cppreference.com/w/cpp/algorithm/binary_search - * \see \p lower_bound - * \see \p upper_bound - * \see \p equal_range - */ -template -__host__ __device__ -bool binary_search(const thrust::detail::execution_policy_base &exec, - ForwardIterator first, - ForwardIterator last, - const T& value, - StrictWeakOrdering comp); - - -/*! \p binary_search is a version of binary search: it attempts to find - * the element value in an ordered range [first, last). - * It returns \c true if an element that is equivalent to \c value - * is present in [first, last) and \c false if no such element - * exists. Specifically, this version returns \c true if and only if - * there exists an iterator \c i in [first, last) such that - * comp(*i, value) and comp(value, *i) are both \c false. - * - * \param first The beginning of the ordered sequence. - * \param last The end of the ordered sequence. - * \param value The value to be searched. - * \param comp The comparison operator. - * \return \c true if an equivalent element exists in [first, last), otherwise \c false. - * - * \tparam ForwardIterator is a model of Forward Iterator. - * \tparam T is comparable to \p ForwardIterator's \c value_type. - * \tparam StrictWeakOrdering is a model of Strict Weak Ordering. - * - * The following code snippet demonstrates how to use \p binary_search - * to search for values in a ordered range. - * - * \code - * #include - * #include - * #include - * ... - * thrust::device_vector input(5); - * - * input[0] = 0; - * input[1] = 2; - * input[2] = 5; - * input[3] = 7; - * input[4] = 8; - * - * thrust::binary_search(input.begin(), input.end(), 0, thrust::less()); // returns true - * thrust::binary_search(input.begin(), input.end(), 1, thrust::less()); // returns false - * thrust::binary_search(input.begin(), input.end(), 2, thrust::less()); // returns true - * thrust::binary_search(input.begin(), input.end(), 3, thrust::less()); // returns false - * thrust::binary_search(input.begin(), input.end(), 8, thrust::less()); // returns true - * thrust::binary_search(input.begin(), input.end(), 9, thrust::less()); // returns false - * \endcode - * - * \see https://en.cppreference.com/w/cpp/algorithm/binary_search - * \see \p lower_bound - * \see \p upper_bound - * \see \p equal_range - */ -template -bool binary_search(ForwardIterator first, - ForwardIterator last, - const T& value, - StrictWeakOrdering comp); - - -/*! \p equal_range is a version of binary search: it attempts to find - * the element value in an ordered range [first, last). The - * value returned by \p equal_range is essentially a combination of - * the values returned by \p lower_bound and \p upper_bound: it returns - * a \p pair of iterators \c i and \c j such that \c i is the first - * position where value could be inserted without violating the - * ordering and \c j is the last position where value could be inserted - * without violating the ordering. It follows that every element in the - * range [i, j) is equivalent to value, and that - * [i, j) is the largest subrange of [first, last) that - * has this property. - * - * This version of \p equal_range returns a \p pair of iterators - * [i, j), where \c i is the furthermost iterator in - * [first, last) such that, for every iterator \c k in - * [first, i), *k < value. \c j is the furthermost - * iterator in [first, last) such that, for every iterator - * \c k in [first, j), value < *k is \c false. - * For every iterator \c k in [i, j), neither - * value < *k nor *k < value is \c true. - * - * The algorithm's execution is parallelized as determined by \p exec. - * - * \param exec The execution policy to use for parallelization. - * \param first The beginning of the ordered sequence. - * \param last The end of the ordered sequence. - * \param value The value to be searched. - * \return A \p pair of iterators [i, j) that define the range of equivalent elements. - * - * \tparam DerivedPolicy The name of the derived execution policy. - * \tparam ForwardIterator is a model of Forward Iterator. - * \tparam LessThanComparable is a model of LessThanComparable. - * - * The following code snippet demonstrates how to use \p equal_range - * to search for values in a ordered range using the \p thrust::device execution policy for parallelization: - * - * \code - * #include - * #include - * #include - * ... - * thrust::device_vector input(5); - * - * input[0] = 0; - * input[1] = 2; - * input[2] = 5; - * input[3] = 7; - * input[4] = 8; - * - * thrust::equal_range(thrust::device, input.begin(), input.end(), 0); // returns [input.begin(), input.begin() + 1) - * thrust::equal_range(thrust::device, input.begin(), input.end(), 1); // returns [input.begin() + 1, input.begin() + 1) - * thrust::equal_range(thrust::device, input.begin(), input.end(), 2); // returns [input.begin() + 1, input.begin() + 2) - * thrust::equal_range(thrust::device, input.begin(), input.end(), 3); // returns [input.begin() + 2, input.begin() + 2) - * thrust::equal_range(thrust::device, input.begin(), input.end(), 8); // returns [input.begin() + 4, input.end) - * thrust::equal_range(thrust::device, input.begin(), input.end(), 9); // returns [input.end(), input.end) - * \endcode - * - * \see https://en.cppreference.com/w/cpp/algorithm/equal_range - * \see \p lower_bound - * \see \p upper_bound - * \see \p binary_search - */ -template -__host__ __device__ -thrust::pair -equal_range(const thrust::detail::execution_policy_base &exec, - ForwardIterator first, - ForwardIterator last, - const LessThanComparable& value); - - -/*! \p equal_range is a version of binary search: it attempts to find - * the element value in an ordered range [first, last). The - * value returned by \p equal_range is essentially a combination of - * the values returned by \p lower_bound and \p upper_bound: it returns - * a \p pair of iterators \c i and \c j such that \c i is the first - * position where value could be inserted without violating the - * ordering and \c j is the last position where value could be inserted - * without violating the ordering. It follows that every element in the - * range [i, j) is equivalent to value, and that - * [i, j) is the largest subrange of [first, last) that - * has this property. - * - * This version of \p equal_range returns a \p pair of iterators - * [i, j), where \c i is the furthermost iterator in - * [first, last) such that, for every iterator \c k in - * [first, i), *k < value. \c j is the furthermost - * iterator in [first, last) such that, for every iterator - * \c k in [first, j), value < *k is \c false. - * For every iterator \c k in [i, j), neither - * value < *k nor *k < value is \c true. - * - * \param first The beginning of the ordered sequence. - * \param last The end of the ordered sequence. - * \param value The value to be searched. - * \return A \p pair of iterators [i, j) that define the range of equivalent elements. - * - * \tparam ForwardIterator is a model of Forward Iterator. - * \tparam LessThanComparable is a model of LessThanComparable. - * - * The following code snippet demonstrates how to use \p equal_range - * to search for values in a ordered range. - * - * \code - * #include - * #include - * ... - * thrust::device_vector input(5); - * - * input[0] = 0; - * input[1] = 2; - * input[2] = 5; - * input[3] = 7; - * input[4] = 8; - * - * thrust::equal_range(input.begin(), input.end(), 0); // returns [input.begin(), input.begin() + 1) - * thrust::equal_range(input.begin(), input.end(), 1); // returns [input.begin() + 1, input.begin() + 1) - * thrust::equal_range(input.begin(), input.end(), 2); // returns [input.begin() + 1, input.begin() + 2) - * thrust::equal_range(input.begin(), input.end(), 3); // returns [input.begin() + 2, input.begin() + 2) - * thrust::equal_range(input.begin(), input.end(), 8); // returns [input.begin() + 4, input.end) - * thrust::equal_range(input.begin(), input.end(), 9); // returns [input.end(), input.end) - * \endcode - * - * \see https://en.cppreference.com/w/cpp/algorithm/equal_range - * \see \p lower_bound - * \see \p upper_bound - * \see \p binary_search - */ -template -thrust::pair -equal_range(ForwardIterator first, - ForwardIterator last, - const LessThanComparable& value); - - -/*! \p equal_range is a version of binary search: it attempts to find - * the element value in an ordered range [first, last). The - * value returned by \p equal_range is essentially a combination of - * the values returned by \p lower_bound and \p upper_bound: it returns - * a \p pair of iterators \c i and \c j such that \c i is the first - * position where value could be inserted without violating the - * ordering and \c j is the last position where value could be inserted - * without violating the ordering. It follows that every element in the - * range [i, j) is equivalent to value, and that - * [i, j) is the largest subrange of [first, last) that - * has this property. - * - * This version of \p equal_range returns a \p pair of iterators - * [i, j). \c i is the furthermost iterator in - * [first, last) such that, for every iterator \c k in - * [first, i), comp(*k, value) is \c true. - * \c j is the furthermost iterator in [first, last) such - * that, for every iterator \c k in [first, last), - * comp(value, *k) is \c false. For every iterator \c k - * in [i, j), neither comp(value, *k) nor - * comp(*k, value) is \c true. - * - * The algorithm's execution is parallelized as determined by \p exec. - * - * \param exec The execution policy to use for parallelization. - * \param first The beginning of the ordered sequence. - * \param last The end of the ordered sequence. - * \param value The value to be searched. - * \param comp The comparison operator. - * \return A \p pair of iterators [i, j) that define the range of equivalent elements. - * - * \tparam DerivedPolicy The name of the derived execution policy. - * \tparam ForwardIterator is a model of Forward Iterator. - * \tparam T is comparable to \p ForwardIterator's \c value_type. - * \tparam StrictWeakOrdering is a model of Strict Weak Ordering. - * - * The following code snippet demonstrates how to use \p equal_range - * to search for values in a ordered range using the \p thrust::device execution policy for parallelization: - * - * \code - * #include - * #include - * #include - * #include - * ... - * thrust::device_vector input(5); - * - * input[0] = 0; - * input[1] = 2; - * input[2] = 5; - * input[3] = 7; - * input[4] = 8; - * - * thrust::equal_range(thrust::device, input.begin(), input.end(), 0, thrust::less()); // returns [input.begin(), input.begin() + 1) - * thrust::equal_range(thrust::device, input.begin(), input.end(), 1, thrust::less()); // returns [input.begin() + 1, input.begin() + 1) - * thrust::equal_range(thrust::device, input.begin(), input.end(), 2, thrust::less()); // returns [input.begin() + 1, input.begin() + 2) - * thrust::equal_range(thrust::device, input.begin(), input.end(), 3, thrust::less()); // returns [input.begin() + 2, input.begin() + 2) - * thrust::equal_range(thrust::device, input.begin(), input.end(), 8, thrust::less()); // returns [input.begin() + 4, input.end) - * thrust::equal_range(thrust::device, input.begin(), input.end(), 9, thrust::less()); // returns [input.end(), input.end) - * \endcode - * - * \see https://en.cppreference.com/w/cpp/algorithm/equal_range - * \see \p lower_bound - * \see \p upper_bound - * \see \p binary_search - */ -template -__host__ __device__ -thrust::pair -equal_range(const thrust::detail::execution_policy_base &exec, - ForwardIterator first, - ForwardIterator last, - const T& value, - StrictWeakOrdering comp); - - -/*! \p equal_range is a version of binary search: it attempts to find - * the element value in an ordered range [first, last). The - * value returned by \p equal_range is essentially a combination of - * the values returned by \p lower_bound and \p upper_bound: it returns - * a \p pair of iterators \c i and \c j such that \c i is the first - * position where value could be inserted without violating the - * ordering and \c j is the last position where value could be inserted - * without violating the ordering. It follows that every element in the - * range [i, j) is equivalent to value, and that - * [i, j) is the largest subrange of [first, last) that - * has this property. - * - * This version of \p equal_range returns a \p pair of iterators - * [i, j). \c i is the furthermost iterator in - * [first, last) such that, for every iterator \c k in - * [first, i), comp(*k, value) is \c true. - * \c j is the furthermost iterator in [first, last) such - * that, for every iterator \c k in [first, last), - * comp(value, *k) is \c false. For every iterator \c k - * in [i, j), neither comp(value, *k) nor - * comp(*k, value) is \c true. - * - * \param first The beginning of the ordered sequence. - * \param last The end of the ordered sequence. - * \param value The value to be searched. - * \param comp The comparison operator. - * \return A \p pair of iterators [i, j) that define the range of equivalent elements. - * - * \tparam ForwardIterator is a model of Forward Iterator. - * \tparam T is comparable to \p ForwardIterator's \c value_type. - * \tparam StrictWeakOrdering is a model of Strict Weak Ordering. - * - * The following code snippet demonstrates how to use \p equal_range - * to search for values in a ordered range. - * - * \code - * #include - * #include - * #include - * ... - * thrust::device_vector input(5); - * - * input[0] = 0; - * input[1] = 2; - * input[2] = 5; - * input[3] = 7; - * input[4] = 8; - * - * thrust::equal_range(input.begin(), input.end(), 0, thrust::less()); // returns [input.begin(), input.begin() + 1) - * thrust::equal_range(input.begin(), input.end(), 1, thrust::less()); // returns [input.begin() + 1, input.begin() + 1) - * thrust::equal_range(input.begin(), input.end(), 2, thrust::less()); // returns [input.begin() + 1, input.begin() + 2) - * thrust::equal_range(input.begin(), input.end(), 3, thrust::less()); // returns [input.begin() + 2, input.begin() + 2) - * thrust::equal_range(input.begin(), input.end(), 8, thrust::less()); // returns [input.begin() + 4, input.end) - * thrust::equal_range(input.begin(), input.end(), 9, thrust::less()); // returns [input.end(), input.end) - * \endcode - * - * \see https://en.cppreference.com/w/cpp/algorithm/equal_range - * \see \p lower_bound - * \see \p upper_bound - * \see \p binary_search - */ -template -thrust::pair -equal_range(ForwardIterator first, - ForwardIterator last, - const T& value, - StrictWeakOrdering comp); - - -/*! \addtogroup vectorized_binary_search Vectorized Searches - * \ingroup binary_search - * \{ - */ - - -////////////////////// -// Vector Functions // -////////////////////// - - -/*! \p lower_bound is a vectorized version of binary search: for each - * iterator \c v in [values_first, values_last) it attempts to - * find the value *v in an ordered range [first, last). - * Specifically, it returns the index of first position where value could - * be inserted without violating the ordering. - * - * The algorithm's execution is parallelized as determined by \p exec. - * - * \param exec The execution policy to use for parallelization. - * \param first The beginning of the ordered sequence. - * \param last The end of the ordered sequence. - * \param values_first The beginning of the search values sequence. - * \param values_last The end of the search values sequence. - * \param result The beginning of the output sequence. - * - * \tparam DerivedPolicy The name of the derived execution policy. - * \tparam ForwardIterator is a model of Forward Iterator. - * \tparam InputIterator is a model of Input Iterator. - * and \c InputIterator's \c value_type is LessThanComparable. - * \tparam OutputIterator is a model of Output Iterator. - * and \c ForwardIterator's difference_type is convertible to \c OutputIterator's \c value_type. - * - * \pre The ranges [first,last) and [result, result + (last - first)) shall not overlap. - * - * The following code snippet demonstrates how to use \p lower_bound - * to search for multiple values in a ordered range using the \p thrust::device execution policy for - * parallelization: - * - * \code - * #include - * #include - * #include - * ... - * thrust::device_vector input(5); - * - * input[0] = 0; - * input[1] = 2; - * input[2] = 5; - * input[3] = 7; - * input[4] = 8; - * - * thrust::device_vector values(6); - * values[0] = 0; - * values[1] = 1; - * values[2] = 2; - * values[3] = 3; - * values[4] = 8; - * values[5] = 9; - * - * thrust::device_vector output(6); - * - * thrust::lower_bound(thrust::device, - * input.begin(), input.end(), - * values.begin(), values.end(), - * output.begin()); - * - * // output is now [0, 1, 1, 2, 4, 5] - * \endcode - * - * \see https://en.cppreference.com/w/cpp/algorithm/lower_bound - * \see \p upper_bound - * \see \p equal_range - * \see \p binary_search - */ -template -__host__ __device__ -OutputIterator lower_bound(const thrust::detail::execution_policy_base &exec, - ForwardIterator first, - ForwardIterator last, - InputIterator values_first, - InputIterator values_last, - OutputIterator result); - - -/*! \p lower_bound is a vectorized version of binary search: for each - * iterator \c v in [values_first, values_last) it attempts to - * find the value *v in an ordered range [first, last). - * Specifically, it returns the index of first position where value could - * be inserted without violating the ordering. - * - * \param first The beginning of the ordered sequence. - * \param last The end of the ordered sequence. - * \param values_first The beginning of the search values sequence. - * \param values_last The end of the search values sequence. - * \param result The beginning of the output sequence. - * - * \tparam ForwardIterator is a model of Forward Iterator. - * \tparam InputIterator is a model of Input Iterator. - * and \c InputIterator's \c value_type is LessThanComparable. - * \tparam OutputIterator is a model of Output Iterator. - * and \c ForwardIterator's difference_type is convertible to \c OutputIterator's \c value_type. - * - * \pre The ranges [first,last) and [result, result + (last - first)) shall not overlap. - * - * The following code snippet demonstrates how to use \p lower_bound - * to search for multiple values in a ordered range. - * - * \code - * #include - * #include - * ... - * thrust::device_vector input(5); - * - * input[0] = 0; - * input[1] = 2; - * input[2] = 5; - * input[3] = 7; - * input[4] = 8; - * - * thrust::device_vector values(6); - * values[0] = 0; - * values[1] = 1; - * values[2] = 2; - * values[3] = 3; - * values[4] = 8; - * values[5] = 9; - * - * thrust::device_vector output(6); - * - * thrust::lower_bound(input.begin(), input.end(), - * values.begin(), values.end(), - * output.begin()); - * - * // output is now [0, 1, 1, 2, 4, 5] - * \endcode - * - * \see https://en.cppreference.com/w/cpp/algorithm/lower_bound - * \see \p upper_bound - * \see \p equal_range - * \see \p binary_search - */ -template -OutputIterator lower_bound(ForwardIterator first, - ForwardIterator last, - InputIterator values_first, - InputIterator values_last, - OutputIterator result); - - -/*! \p lower_bound is a vectorized version of binary search: for each - * iterator \c v in [values_first, values_last) it attempts to - * find the value *v in an ordered range [first, last). - * Specifically, it returns the index of first position where value could - * be inserted without violating the ordering. This version of - * \p lower_bound uses function object \c comp for comparison. - * - * The algorithm's execution is parallelized as determined by \p exec. - * - * \param exec The execution policy to use for parallelization. - * \param first The beginning of the ordered sequence. - * \param last The end of the ordered sequence. - * \param values_first The beginning of the search values sequence. - * \param values_last The end of the search values sequence. - * \param result The beginning of the output sequence. - * \param comp The comparison operator. - * - * \tparam DerivedPolicy The name of the derived execution policy. - * \tparam ForwardIterator is a model of Forward Iterator. - * \tparam InputIterator is a model of Input Iterator. - * and \c InputIterator's \c value_type is comparable to \p ForwardIterator's \c value_type. - * \tparam OutputIterator is a model of Output Iterator. - * and \c ForwardIterator's difference_type is convertible to \c OutputIterator's \c value_type. - * \tparam StrictWeakOrdering is a model of Strict Weak Ordering. - * - * \pre The ranges [first,last) and [result, result + (last - first)) shall not overlap. - * - * The following code snippet demonstrates how to use \p lower_bound - * to search for multiple values in a ordered range. - * - * \code - * #include - * #include - * #include - * #include - * ... - * thrust::device_vector input(5); - * - * input[0] = 0; - * input[1] = 2; - * input[2] = 5; - * input[3] = 7; - * input[4] = 8; - * - * thrust::device_vector values(6); - * values[0] = 0; - * values[1] = 1; - * values[2] = 2; - * values[3] = 3; - * values[4] = 8; - * values[5] = 9; - * - * thrust::device_vector output(6); - * - * thrust::lower_bound(input.begin(), input.end(), - * values.begin(), values.end(), - * output.begin(), - * thrust::less()); - * - * // output is now [0, 1, 1, 2, 4, 5] - * \endcode - * - * \see https://en.cppreference.com/w/cpp/algorithm/lower_bound - * \see \p upper_bound - * \see \p equal_range - * \see \p binary_search - */ -template -__host__ __device__ -OutputIterator lower_bound(const thrust::detail::execution_policy_base &exec, - ForwardIterator first, - ForwardIterator last, - InputIterator values_first, - InputIterator values_last, - OutputIterator result, - StrictWeakOrdering comp); - - -/*! \p lower_bound is a vectorized version of binary search: for each - * iterator \c v in [values_first, values_last) it attempts to - * find the value *v in an ordered range [first, last). - * Specifically, it returns the index of first position where value could - * be inserted without violating the ordering. This version of - * \p lower_bound uses function object \c comp for comparison. - * - * \param first The beginning of the ordered sequence. - * \param last The end of the ordered sequence. - * \param values_first The beginning of the search values sequence. - * \param values_last The end of the search values sequence. - * \param result The beginning of the output sequence. - * \param comp The comparison operator. - * - * \tparam ForwardIterator is a model of Forward Iterator. - * \tparam InputIterator is a model of Input Iterator. - * and \c InputIterator's \c value_type is comparable to \p ForwardIterator's \c value_type. - * \tparam OutputIterator is a model of Output Iterator. - * and \c ForwardIterator's difference_type is convertible to \c OutputIterator's \c value_type. - * \tparam StrictWeakOrdering is a model of Strict Weak Ordering. - * - * \pre The ranges [first,last) and [result, result + (last - first)) shall not overlap. - * - * The following code snippet demonstrates how to use \p lower_bound - * to search for multiple values in a ordered range. - * - * \code - * #include - * #include - * #include - * ... - * thrust::device_vector input(5); - * - * input[0] = 0; - * input[1] = 2; - * input[2] = 5; - * input[3] = 7; - * input[4] = 8; - * - * thrust::device_vector values(6); - * values[0] = 0; - * values[1] = 1; - * values[2] = 2; - * values[3] = 3; - * values[4] = 8; - * values[5] = 9; - * - * thrust::device_vector output(6); - * - * thrust::lower_bound(input.begin(), input.end(), - * values.begin(), values.end(), - * output.begin(), - * thrust::less()); - * - * // output is now [0, 1, 1, 2, 4, 5] - * \endcode - * - * \see https://en.cppreference.com/w/cpp/algorithm/lower_bound - * \see \p upper_bound - * \see \p equal_range - * \see \p binary_search - */ -template -OutputIterator lower_bound(ForwardIterator first, - ForwardIterator last, - InputIterator values_first, - InputIterator values_last, - OutputIterator result, - StrictWeakOrdering comp); - - -/*! \p upper_bound is a vectorized version of binary search: for each - * iterator \c v in [values_first, values_last) it attempts to - * find the value *v in an ordered range [first, last). - * Specifically, it returns the index of last position where value could - * be inserted without violating the ordering. - * - * The algorithm's execution is parallelized as determined by \p exec. - * - * \param exec The execution policy to use for parallelization. - * \param first The beginning of the ordered sequence. - * \param last The end of the ordered sequence. - * \param values_first The beginning of the search values sequence. - * \param values_last The end of the search values sequence. - * \param result The beginning of the output sequence. - * - * \tparam DerivedPolicy The name of the derived execution policy. - * \tparam ForwardIterator is a model of Forward Iterator. - * \tparam InputIterator is a model of Input Iterator. - * and \c InputIterator's \c value_type is LessThanComparable. - * \tparam OutputIterator is a model of Output Iterator. - * and \c ForwardIterator's difference_type is convertible to \c OutputIterator's \c value_type. - * - * \pre The ranges [first,last) and [result, result + (last - first)) shall not overlap. - * - * The following code snippet demonstrates how to use \p upper_bound - * to search for multiple values in a ordered range using the \p thrust::device execution policy for - * parallelization: - * - * \code - * #include - * #include - * #include - * ... - * thrust::device_vector input(5); - * - * input[0] = 0; - * input[1] = 2; - * input[2] = 5; - * input[3] = 7; - * input[4] = 8; - * - * thrust::device_vector values(6); - * values[0] = 0; - * values[1] = 1; - * values[2] = 2; - * values[3] = 3; - * values[4] = 8; - * values[5] = 9; - * - * thrust::device_vector output(6); - * - * thrust::upper_bound(thrust::device, - * input.begin(), input.end(), - * values.begin(), values.end(), - * output.begin()); - * - * // output is now [1, 1, 2, 2, 5, 5] - * \endcode - * - * \see https://en.cppreference.com/w/cpp/algorithm/upper_bound - * \see \p upper_bound - * \see \p equal_range - * \see \p binary_search - */ -template -__host__ __device__ -OutputIterator upper_bound(const thrust::detail::execution_policy_base &exec, - ForwardIterator first, - ForwardIterator last, - InputIterator values_first, - InputIterator values_last, - OutputIterator result); - - -/*! \p upper_bound is a vectorized version of binary search: for each - * iterator \c v in [values_first, values_last) it attempts to - * find the value *v in an ordered range [first, last). - * Specifically, it returns the index of last position where value could - * be inserted without violating the ordering. - * - * \param first The beginning of the ordered sequence. - * \param last The end of the ordered sequence. - * \param values_first The beginning of the search values sequence. - * \param values_last The end of the search values sequence. - * \param result The beginning of the output sequence. - * - * \tparam ForwardIterator is a model of Forward Iterator. - * \tparam InputIterator is a model of Input Iterator. - * and \c InputIterator's \c value_type is LessThanComparable. - * \tparam OutputIterator is a model of Output Iterator. - * and \c ForwardIterator's difference_type is convertible to \c OutputIterator's \c value_type. - * - * \pre The ranges [first,last) and [result, result + (last - first)) shall not overlap. - * - * The following code snippet demonstrates how to use \p upper_bound - * to search for multiple values in a ordered range. - * - * \code - * #include - * #include - * ... - * thrust::device_vector input(5); - * - * input[0] = 0; - * input[1] = 2; - * input[2] = 5; - * input[3] = 7; - * input[4] = 8; - * - * thrust::device_vector values(6); - * values[0] = 0; - * values[1] = 1; - * values[2] = 2; - * values[3] = 3; - * values[4] = 8; - * values[5] = 9; - * - * thrust::device_vector output(6); - * - * thrust::upper_bound(input.begin(), input.end(), - * values.begin(), values.end(), - * output.begin()); - * - * // output is now [1, 1, 2, 2, 5, 5] - * \endcode - * - * \see https://en.cppreference.com/w/cpp/algorithm/upper_bound - * \see \p upper_bound - * \see \p equal_range - * \see \p binary_search - */ -template -OutputIterator upper_bound(ForwardIterator first, - ForwardIterator last, - InputIterator values_first, - InputIterator values_last, - OutputIterator result); - - -/*! \p upper_bound is a vectorized version of binary search: for each - * iterator \c v in [values_first, values_last) it attempts to - * find the value *v in an ordered range [first, last). - * Specifically, it returns the index of first position where value could - * be inserted without violating the ordering. This version of - * \p upper_bound uses function object \c comp for comparison. - * - * The algorithm's execution is parallelized as determined by \p exec. - * - * \param exec The execution policy to use for parallelization. - * \param first The beginning of the ordered sequence. - * \param last The end of the ordered sequence. - * \param values_first The beginning of the search values sequence. - * \param values_last The end of the search values sequence. - * \param result The beginning of the output sequence. - * \param comp The comparison operator. - * - * \tparam DerivedPolicy The name of the derived execution policy. - * \tparam ForwardIterator is a model of Forward Iterator. - * \tparam InputIterator is a model of Input Iterator. - * and \c InputIterator's \c value_type is comparable to \p ForwardIterator's \c value_type. - * \tparam OutputIterator is a model of Output Iterator. - * and \c ForwardIterator's difference_type is convertible to \c OutputIterator's \c value_type. - * \tparam StrictWeakOrdering is a model of Strict Weak Ordering. - * - * \pre The ranges [first,last) and [result, result + (last - first)) shall not overlap. - * - * The following code snippet demonstrates how to use \p upper_bound - * to search for multiple values in a ordered range using the \p thrust::device execution policy for - * parallelization: - * - * \code - * #include - * #include - * #include - * #include - * ... - * thrust::device_vector input(5); - * - * input[0] = 0; - * input[1] = 2; - * input[2] = 5; - * input[3] = 7; - * input[4] = 8; - * - * thrust::device_vector values(6); - * values[0] = 0; - * values[1] = 1; - * values[2] = 2; - * values[3] = 3; - * values[4] = 8; - * values[5] = 9; - * - * thrust::device_vector output(6); - * - * thrust::upper_bound(thrust::device, - * input.begin(), input.end(), - * values.begin(), values.end(), - * output.begin(), - * thrust::less()); - * - * // output is now [1, 1, 2, 2, 5, 5] - * \endcode - * - * \see https://en.cppreference.com/w/cpp/algorithm/upper_bound - * \see \p lower_bound - * \see \p equal_range - * \see \p binary_search - */ -template -__host__ __device__ -OutputIterator upper_bound(const thrust::detail::execution_policy_base &exec, - ForwardIterator first, - ForwardIterator last, - InputIterator values_first, - InputIterator values_last, - OutputIterator result, - StrictWeakOrdering comp); - - -/*! \p upper_bound is a vectorized version of binary search: for each - * iterator \c v in [values_first, values_last) it attempts to - * find the value *v in an ordered range [first, last). - * Specifically, it returns the index of first position where value could - * be inserted without violating the ordering. This version of - * \p upper_bound uses function object \c comp for comparison. - * - * \param first The beginning of the ordered sequence. - * \param last The end of the ordered sequence. - * \param values_first The beginning of the search values sequence. - * \param values_last The end of the search values sequence. - * \param result The beginning of the output sequence. - * \param comp The comparison operator. - * - * \tparam ForwardIterator is a model of Forward Iterator. - * \tparam InputIterator is a model of Input Iterator. - * and \c InputIterator's \c value_type is comparable to \p ForwardIterator's \c value_type. - * \tparam OutputIterator is a model of Output Iterator. - * and \c ForwardIterator's difference_type is convertible to \c OutputIterator's \c value_type. - * \tparam StrictWeakOrdering is a model of Strict Weak Ordering. - * - * \pre The ranges [first,last) and [result, result + (last - first)) shall not overlap. - * - * The following code snippet demonstrates how to use \p upper_bound - * to search for multiple values in a ordered range. - * - * \code - * #include - * #include - * #include - * ... - * thrust::device_vector input(5); - * - * input[0] = 0; - * input[1] = 2; - * input[2] = 5; - * input[3] = 7; - * input[4] = 8; - * - * thrust::device_vector values(6); - * values[0] = 0; - * values[1] = 1; - * values[2] = 2; - * values[3] = 3; - * values[4] = 8; - * values[5] = 9; - * - * thrust::device_vector output(6); - * - * thrust::upper_bound(input.begin(), input.end(), - * values.begin(), values.end(), - * output.begin(), - * thrust::less()); - * - * // output is now [1, 1, 2, 2, 5, 5] - * \endcode - * - * \see https://en.cppreference.com/w/cpp/algorithm/upper_bound - * \see \p lower_bound - * \see \p equal_range - * \see \p binary_search - */ -template -OutputIterator upper_bound(ForwardIterator first, - ForwardIterator last, - InputIterator values_first, - InputIterator values_last, - OutputIterator result, - StrictWeakOrdering comp); - - -/*! \p binary_search is a vectorized version of binary search: for each - * iterator \c v in [values_first, values_last) it attempts to - * find the value *v in an ordered range [first, last). - * It returns \c true if an element that is equivalent to \c value - * is present in [first, last) and \c false if no such element - * exists. - * - * The algorithm's execution is parallelized as determined by \p exec. - * - * \param exec The execution policy to use for parallelization. - * \param first The beginning of the ordered sequence. - * \param last The end of the ordered sequence. - * \param values_first The beginning of the search values sequence. - * \param values_last The end of the search values sequence. - * \param result The beginning of the output sequence. - * - * \tparam DerivedPolicy The name of the derived execution policy. - * \tparam ForwardIterator is a model of Forward Iterator. - * \tparam InputIterator is a model of Input Iterator. - * and \c InputIterator's \c value_type is LessThanComparable. - * \tparam OutputIterator is a model of Output Iterator. - * and bool is convertible to \c OutputIterator's \c value_type. - * - * \pre The ranges [first,last) and [result, result + (last - first)) shall not overlap. - * - * The following code snippet demonstrates how to use \p binary_search - * to search for multiple values in a ordered range using the \p thrust::device execution policy for - * parallelization: - * - * \code - * #include - * #include - * #include - * ... - * thrust::device_vector input(5); - * - * input[0] = 0; - * input[1] = 2; - * input[2] = 5; - * input[3] = 7; - * input[4] = 8; - * - * thrust::device_vector values(6); - * values[0] = 0; - * values[1] = 1; - * values[2] = 2; - * values[3] = 3; - * values[4] = 8; - * values[5] = 9; - * - * thrust::device_vector output(6); - * - * thrust::binary_search(thrust::device, - * input.begin(), input.end(), - * values.begin(), values.end(), - * output.begin()); - * - * // output is now [true, false, true, false, true, false] - * \endcode - * - * \see https://en.cppreference.com/w/cpp/algorithm/binary_search - * \see \p lower_bound - * \see \p upper_bound - * \see \p equal_range - */ -template -__host__ __device__ -OutputIterator binary_search(const thrust::detail::execution_policy_base &exec, - ForwardIterator first, - ForwardIterator last, - InputIterator values_first, - InputIterator values_last, - OutputIterator result); - - -/*! \p binary_search is a vectorized version of binary search: for each - * iterator \c v in [values_first, values_last) it attempts to - * find the value *v in an ordered range [first, last). - * It returns \c true if an element that is equivalent to \c value - * is present in [first, last) and \c false if no such element - * exists. - * - * \param first The beginning of the ordered sequence. - * \param last The end of the ordered sequence. - * \param values_first The beginning of the search values sequence. - * \param values_last The end of the search values sequence. - * \param result The beginning of the output sequence. - * - * \tparam ForwardIterator is a model of Forward Iterator. - * \tparam InputIterator is a model of Input Iterator. - * and \c InputIterator's \c value_type is LessThanComparable. - * \tparam OutputIterator is a model of Output Iterator. - * and bool is convertible to \c OutputIterator's \c value_type. - * - * \pre The ranges [first,last) and [result, result + (last - first)) shall not overlap. - * - * The following code snippet demonstrates how to use \p binary_search - * to search for multiple values in a ordered range. - * - * \code - * #include - * #include - * ... - * thrust::device_vector input(5); - * - * input[0] = 0; - * input[1] = 2; - * input[2] = 5; - * input[3] = 7; - * input[4] = 8; - * - * thrust::device_vector values(6); - * values[0] = 0; - * values[1] = 1; - * values[2] = 2; - * values[3] = 3; - * values[4] = 8; - * values[5] = 9; - * - * thrust::device_vector output(6); - * - * thrust::binary_search(input.begin(), input.end(), - * values.begin(), values.end(), - * output.begin()); - * - * // output is now [true, false, true, false, true, false] - * \endcode - * - * \see https://en.cppreference.com/w/cpp/algorithm/binary_search - * \see \p lower_bound - * \see \p upper_bound - * \see \p equal_range - */ -template -OutputIterator binary_search(ForwardIterator first, - ForwardIterator last, - InputIterator values_first, - InputIterator values_last, - OutputIterator result); - - -/*! \p binary_search is a vectorized version of binary search: for each - * iterator \c v in [values_first, values_last) it attempts to - * find the value *v in an ordered range [first, last). - * It returns \c true if an element that is equivalent to \c value - * is present in [first, last) and \c false if no such element - * exists. This version of \p binary_search uses function object - * \c comp for comparison. - * - * The algorithm's execution is parallelized as determined by \p exec. - * - * \param exec The execution policy to use for parallelization. - * \param first The beginning of the ordered sequence. - * \param last The end of the ordered sequence. - * \param values_first The beginning of the search values sequence. - * \param values_last The end of the search values sequence. - * \param result The beginning of the output sequence. - * \param comp The comparison operator. - * - * \tparam DerivedPolicy The name of the derived execution policy. - * \tparam ForwardIterator is a model of Forward Iterator. - * \tparam InputIterator is a model of Input Iterator. - * and \c InputIterator's \c value_type is LessThanComparable. - * \tparam OutputIterator is a model of Output Iterator. - * and bool is convertible to \c OutputIterator's \c value_type. - * \tparam StrictWeakOrdering is a model of Strict Weak Ordering. - * - * \pre The ranges [first,last) and [result, result + (last - first)) shall not overlap. - * - * The following code snippet demonstrates how to use \p binary_search - * to search for multiple values in a ordered range using the \p thrust::device execution policy for - * parallelization: - * - * \code - * #include - * #include - * #include - * #include - * ... - * thrust::device_vector input(5); - * - * input[0] = 0; - * input[1] = 2; - * input[2] = 5; - * input[3] = 7; - * input[4] = 8; - * - * thrust::device_vector values(6); - * values[0] = 0; - * values[1] = 1; - * values[2] = 2; - * values[3] = 3; - * values[4] = 8; - * values[5] = 9; - * - * thrust::device_vector output(6); - * - * thrust::binary_search(thrust::device, - * input.begin(), input.end(), - * values.begin(), values.end(), - * output.begin(), - * thrust::less()); - * - * // output is now [true, false, true, false, true, false] - * \endcode - * - * \see https://en.cppreference.com/w/cpp/algorithm/binary_search - * \see \p lower_bound - * \see \p upper_bound - * \see \p equal_range - */ -template -__host__ __device__ -OutputIterator binary_search(const thrust::detail::execution_policy_base &exec, - ForwardIterator first, - ForwardIterator last, - InputIterator values_first, - InputIterator values_last, - OutputIterator result, - StrictWeakOrdering comp); - - -/*! \p binary_search is a vectorized version of binary search: for each - * iterator \c v in [values_first, values_last) it attempts to - * find the value *v in an ordered range [first, last). - * It returns \c true if an element that is equivalent to \c value - * is present in [first, last) and \c false if no such element - * exists. This version of \p binary_search uses function object - * \c comp for comparison. - * - * \param first The beginning of the ordered sequence. - * \param last The end of the ordered sequence. - * \param values_first The beginning of the search values sequence. - * \param values_last The end of the search values sequence. - * \param result The beginning of the output sequence. - * \param comp The comparison operator. - * - * \tparam ForwardIterator is a model of Forward Iterator. - * \tparam InputIterator is a model of Input Iterator. - * and \c InputIterator's \c value_type is LessThanComparable. - * \tparam OutputIterator is a model of Output Iterator. - * and bool is convertible to \c OutputIterator's \c value_type. - * \tparam StrictWeakOrdering is a model of Strict Weak Ordering. - * - * \pre The ranges [first,last) and [result, result + (last - first)) shall not overlap. - * - * The following code snippet demonstrates how to use \p binary_search - * to search for multiple values in a ordered range. - * - * \code - * #include - * #include - * #include - * ... - * thrust::device_vector input(5); - * - * input[0] = 0; - * input[1] = 2; - * input[2] = 5; - * input[3] = 7; - * input[4] = 8; - * - * thrust::device_vector values(6); - * values[0] = 0; - * values[1] = 1; - * values[2] = 2; - * values[3] = 3; - * values[4] = 8; - * values[5] = 9; - * - * thrust::device_vector output(6); - * - * thrust::binary_search(input.begin(), input.end(), - * values.begin(), values.end(), - * output.begin(), - * thrust::less()); - * - * // output is now [true, false, true, false, true, false] - * \endcode - * - * \see https://en.cppreference.com/w/cpp/algorithm/binary_search - * \see \p lower_bound - * \see \p upper_bound - * \see \p equal_range - */ -template -OutputIterator binary_search(ForwardIterator first, - ForwardIterator last, - InputIterator values_first, - InputIterator values_last, - OutputIterator result, - StrictWeakOrdering comp); - - -/*! \} // end vectorized_binary_search - */ - - -/*! \} // end binary_search - */ - - -/*! \} // end searching - */ - -THRUST_NAMESPACE_END - -#include - diff --git a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/thrust/cmake/FindTBB.cmake b/IfcPlusPlus/src/external/manifold/src/third_party/thrust/thrust/cmake/FindTBB.cmake deleted file mode 100644 index 2ee350d3e..000000000 --- a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/thrust/cmake/FindTBB.cmake +++ /dev/null @@ -1,445 +0,0 @@ -# - Find ThreadingBuildingBlocks include dirs and libraries -# Use this module by invoking find_package with the form: -# find_package(TBB -# [REQUIRED] # Fail with error if TBB is not found -# ) # -# Once done, this will define -# -# TBB_FOUND - system has TBB -# TBB_INCLUDE_DIRS - the TBB include directories -# TBB_LIBRARIES - TBB libraries to be lined, doesn't include malloc or -# malloc proxy -# TBB::tbb - imported target for the TBB library -# -# TBB_VERSION - Product Version Number ("MAJOR.MINOR") -# TBB_VERSION_MAJOR - Major Product Version Number -# TBB_VERSION_MINOR - Minor Product Version Number -# TBB_INTERFACE_VERSION - Engineering Focused Version Number -# TBB_COMPATIBLE_INTERFACE_VERSION - The oldest major interface version -# still supported. This uses the engineering -# focused interface version numbers. -# -# TBB_MALLOC_FOUND - system has TBB malloc library -# TBB_MALLOC_INCLUDE_DIRS - the TBB malloc include directories -# TBB_MALLOC_LIBRARIES - The TBB malloc libraries to be lined -# TBB::malloc - imported target for the TBB malloc library -# -# TBB_MALLOC_PROXY_FOUND - system has TBB malloc proxy library -# TBB_MALLOC_PROXY_INCLUDE_DIRS = the TBB malloc proxy include directories -# TBB_MALLOC_PROXY_LIBRARIES - The TBB malloc proxy libraries to be lined -# TBB::malloc_proxy - imported target for the TBB malloc proxy library -# -# -# This module reads hints about search locations from variables: -# ENV TBB_ARCH_PLATFORM - for eg. set it to "mic" for Xeon Phi builds -# ENV TBB_ROOT or just TBB_ROOT - root directory of tbb installation -# ENV TBB_BUILD_PREFIX - specifies the build prefix for user built tbb -# libraries. Should be specified with ENV TBB_ROOT -# and optionally... -# ENV TBB_BUILD_DIR - if build directory is different than ${TBB_ROOT}/build -# -# -# Modified by Robert Maynard from the original OGRE source -# -#------------------------------------------------------------------- -# This file is part of the CMake build system for OGRE -# (Object-oriented Graphics Rendering Engine) -# For the latest info, see http://www.ogre3d.org/ -# -# The contents of this file are placed in the public domain. Feel -# free to make use of it in any way you like. -#------------------------------------------------------------------- -# -#============================================================================= -# Copyright 2010-2012 Kitware, Inc. -# Copyright 2012 Rolf Eike Beer -# -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. -#============================================================================= -# (To distribute this file outside of CMake, substitute the full -# License text for the above reference.) - - -#============================================================================= -# FindTBB helper functions and macros -# - -#==================================================== -# Fix the library path in case it is a linker script -#==================================================== -function(tbb_extract_real_library library real_library) - if(NOT UNIX OR NOT EXISTS ${library}) - set(${real_library} "${library}" PARENT_SCOPE) - return() - endif() - - #Read in the first 4 bytes and see if they are the ELF magic number - set(_elf_magic "7f454c46") - file(READ ${library} _hex_data OFFSET 0 LIMIT 4 HEX) - if(_hex_data STREQUAL _elf_magic) - #we have opened a elf binary so this is what - #we should link to - set(${real_library} "${library}" PARENT_SCOPE) - return() - endif() - - file(READ ${library} _data OFFSET 0 LIMIT 1024) - if("${_data}" MATCHES "INPUT \\(([^(]+)\\)") - #extract out the .so name from REGEX MATCH command - set(_proper_so_name "${CMAKE_MATCH_1}") - - #construct path to the real .so which is presumed to be in the same directory - #as the input file - get_filename_component(_so_dir "${library}" DIRECTORY) - set(${real_library} "${_so_dir}/${_proper_so_name}" PARENT_SCOPE) - else() - #unable to determine what this library is so just hope everything works - #and pass it unmodified. - set(${real_library} "${library}" PARENT_SCOPE) - endif() -endfunction() - -#=============================================== -# Do the final processing for the package find. -#=============================================== -macro(findpkg_finish PREFIX TARGET_NAME) - if (${PREFIX}_INCLUDE_DIR AND ${PREFIX}_LIBRARY) - set(${PREFIX}_FOUND TRUE) - set (${PREFIX}_INCLUDE_DIRS ${${PREFIX}_INCLUDE_DIR}) - set (${PREFIX}_LIBRARIES ${${PREFIX}_LIBRARY}) - else () - if (${PREFIX}_FIND_REQUIRED) - message(FATAL_ERROR "Required library ${PREFIX} not found.") - elseif (NOT ${PREFIX}_FIND_QUIETLY) - message("Library ${PREFIX} not found.") - endif() - return() - endif () - - if (NOT TARGET "TBB::${TARGET_NAME}") - if (${PREFIX}_LIBRARY_RELEASE) - tbb_extract_real_library(${${PREFIX}_LIBRARY_RELEASE} real_release) - endif () - if (${PREFIX}_LIBRARY_DEBUG) - tbb_extract_real_library(${${PREFIX}_LIBRARY_DEBUG} real_debug) - endif () - add_library(TBB::${TARGET_NAME} UNKNOWN IMPORTED) - set_target_properties(TBB::${TARGET_NAME} PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${${PREFIX}_INCLUDE_DIR}") - if (${PREFIX}_LIBRARY_DEBUG AND ${PREFIX}_LIBRARY_RELEASE) - set_target_properties(TBB::${TARGET_NAME} PROPERTIES - IMPORTED_LOCATION "${real_release}" - IMPORTED_LOCATION_DEBUG "${real_debug}" - IMPORTED_LOCATION_RELEASE "${real_release}") - elseif (${PREFIX}_LIBRARY_RELEASE) - set_target_properties(TBB::${TARGET_NAME} PROPERTIES - IMPORTED_LOCATION "${real_release}") - elseif (${PREFIX}_LIBRARY_DEBUG) - set_target_properties(TBB::${TARGET_NAME} PROPERTIES - IMPORTED_LOCATION "${real_debug}") - endif () - endif () - - #mark the following variables as internal variables - mark_as_advanced(${PREFIX}_INCLUDE_DIR - ${PREFIX}_LIBRARY - ${PREFIX}_LIBRARY_DEBUG - ${PREFIX}_LIBRARY_RELEASE) -endmacro() - -#=============================================== -# Generate debug names from given release names -#=============================================== -macro(get_debug_names PREFIX) - foreach(i ${${PREFIX}}) - set(${PREFIX}_DEBUG ${${PREFIX}_DEBUG} ${i}d ${i}D ${i}_d ${i}_D ${i}_debug ${i}) - endforeach() -endmacro() - -#=============================================== -# See if we have env vars to help us find tbb -#=============================================== -macro(getenv_path VAR) - set(ENV_${VAR} $ENV{${VAR}}) - # replace won't work if var is blank - if (ENV_${VAR}) - string( REGEX REPLACE "\\\\" "/" ENV_${VAR} ${ENV_${VAR}} ) - endif () -endmacro() - -#=============================================== -# Couple a set of release AND debug libraries -#=============================================== -macro(make_library_set PREFIX) - if (${PREFIX}_RELEASE AND ${PREFIX}_DEBUG) - set(${PREFIX} optimized ${${PREFIX}_RELEASE} debug ${${PREFIX}_DEBUG}) - elseif (${PREFIX}_RELEASE) - set(${PREFIX} ${${PREFIX}_RELEASE}) - elseif (${PREFIX}_DEBUG) - set(${PREFIX} ${${PREFIX}_DEBUG}) - endif () -endmacro() - - -#============================================================================= -# Now to actually find TBB -# - -# Get path, convert backslashes as ${ENV_${var}} -getenv_path(TBB_ROOT) - -# initialize search paths -set(TBB_PREFIX_PATH ${TBB_ROOT} ${ENV_TBB_ROOT}) -set(TBB_INC_SEARCH_PATH "") -set(TBB_LIB_SEARCH_PATH "") - - -# If user built from sources -set(TBB_BUILD_PREFIX $ENV{TBB_BUILD_PREFIX}) -if (TBB_BUILD_PREFIX AND ENV_TBB_ROOT) - getenv_path(TBB_BUILD_DIR) - if (NOT ENV_TBB_BUILD_DIR) - set(ENV_TBB_BUILD_DIR ${ENV_TBB_ROOT}/build) - endif () - - # include directory under ${ENV_TBB_ROOT}/include - list(APPEND TBB_LIB_SEARCH_PATH - ${ENV_TBB_BUILD_DIR}/${TBB_BUILD_PREFIX}_release - ${ENV_TBB_BUILD_DIR}/${TBB_BUILD_PREFIX}_debug) -endif () - - -# For Windows, let's assume that the user might be using the precompiled -# TBB packages from the main website. These use a rather awkward directory -# structure (at least for automatically finding the right files) depending -# on platform and compiler, but we'll do our best to accommodate it. -# Not adding the same effort for the precompiled linux builds, though. Those -# have different versions for CC compiler versions and linux kernels which -# will never adequately match the user's setup, so there is no feasible way -# to detect the "best" version to use. The user will have to manually -# select the right files. (Chances are the distributions are shipping their -# custom version of tbb, anyway, so the problem is probably nonexistent.) -if (WIN32 AND MSVC) - set(COMPILER_PREFIX "vc7.1") - if (MSVC_VERSION EQUAL 1400) - set(COMPILER_PREFIX "vc8") - elseif(MSVC_VERSION EQUAL 1500) - set(COMPILER_PREFIX "vc9") - elseif(MSVC_VERSION EQUAL 1600) - set(COMPILER_PREFIX "vc10") - elseif(MSVC_VERSION EQUAL 1700) - set(COMPILER_PREFIX "vc11") - elseif(MSVC_VERSION EQUAL 1800) - set(COMPILER_PREFIX "vc12") - elseif(MSVC_VERSION GREATER_EQUAL 1900 AND MSVC_VERSION LESS_EQUAL 1929) - # 1900-1925 actually spans three Visual Studio versions: - # 1900 = VS 14.0 (v140 toolset) a.k.a. MSVC 2015 - # 1910-1919 = VS 15.0 (v141 toolset) a.k.a. MSVC 2017 - # 1920-1929 = VS 16.0 (v142 toolset) a.k.a. MSVC 2019 - # - # But these are binary compatible and TBB's open source distribution only - # ships a single vs14 lib (as of 2020.0) - set(COMPILER_PREFIX "vc14") - else() - # The next poor soul who finds themselves having to decode visual studio - # version conventions may find these helpful: - # - https://cmake.org/cmake/help/latest/variable/MSVC_VERSION.html - # - https://en.wikipedia.org/wiki/Microsoft_Visual_C%2B%2B#Internal_version_numbering - message(AUTHOR_WARNING - "Unrecognized MSVC version (${MSVC_VERSION}). " - "Please update FindTBB.cmake. " - "Some TBB_* CMake variables may need to be set manually." - ) - endif () - - # for each prefix path, add ia32/64\${COMPILER_PREFIX}\lib to the lib search path - foreach (dir IN LISTS TBB_PREFIX_PATH) - if (CMAKE_CL_64) - list(APPEND TBB_LIB_SEARCH_PATH ${dir}/ia64/${COMPILER_PREFIX}/lib) - list(APPEND TBB_LIB_SEARCH_PATH ${dir}/lib/ia64/${COMPILER_PREFIX}) - list(APPEND TBB_LIB_SEARCH_PATH ${dir}/intel64/${COMPILER_PREFIX}/lib) - list(APPEND TBB_LIB_SEARCH_PATH ${dir}/lib/intel64/${COMPILER_PREFIX}) - else () - list(APPEND TBB_LIB_SEARCH_PATH ${dir}/ia32/${COMPILER_PREFIX}/lib) - list(APPEND TBB_LIB_SEARCH_PATH ${dir}/lib/ia32/${COMPILER_PREFIX}) - endif () - endforeach () -endif () - -# For OS X binary distribution, choose libc++ based libraries for Mavericks (10.9) -# and above and AppleClang -if (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND - NOT CMAKE_SYSTEM_VERSION VERSION_LESS 13.0) - set (USE_LIBCXX OFF) - cmake_policy(GET CMP0025 POLICY_VAR) - - if (POLICY_VAR STREQUAL "NEW") - if (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") - set (USE_LIBCXX ON) - endif () - else () - if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") - set (USE_LIBCXX ON) - endif () - endif () - - if (USE_LIBCXX) - foreach (dir IN LISTS TBB_PREFIX_PATH) - list (APPEND TBB_LIB_SEARCH_PATH ${dir}/lib/libc++ ${dir}/libc++/lib) - endforeach () - endif () -endif () - -# check compiler ABI -if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - set(COMPILER_PREFIX) - if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.7) - list(APPEND COMPILER_PREFIX "gcc4.7") - endif() - if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.4) - list(APPEND COMPILER_PREFIX "gcc4.4") - endif() - list(APPEND COMPILER_PREFIX "gcc4.1") -elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") - set(COMPILER_PREFIX) - if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.6) - list(APPEND COMPILER_PREFIX "gcc4.7") - endif() - list(APPEND COMPILER_PREFIX "gcc4.4") -else() # Assume compatibility with 4.4 for other compilers - list(APPEND COMPILER_PREFIX "gcc4.4") -endif () - -# if platform architecture is explicitly specified -set(TBB_ARCH_PLATFORM $ENV{TBB_ARCH_PLATFORM}) -if (TBB_ARCH_PLATFORM) - foreach (dir IN LISTS TBB_PREFIX_PATH) - list(APPEND TBB_LIB_SEARCH_PATH ${dir}/${TBB_ARCH_PLATFORM}/lib) - list(APPEND TBB_LIB_SEARCH_PATH ${dir}/lib/${TBB_ARCH_PLATFORM}) - endforeach () -endif () - -foreach (dir IN LISTS TBB_PREFIX_PATH) - foreach (prefix IN LISTS COMPILER_PREFIX) - if (CMAKE_SIZEOF_VOID_P EQUAL 8) - list(APPEND TBB_LIB_SEARCH_PATH ${dir}/lib/intel64) - list(APPEND TBB_LIB_SEARCH_PATH ${dir}/lib/intel64/${prefix}) - list(APPEND TBB_LIB_SEARCH_PATH ${dir}/intel64/lib) - list(APPEND TBB_LIB_SEARCH_PATH ${dir}/intel64/${prefix}/lib) - else () - list(APPEND TBB_LIB_SEARCH_PATH ${dir}/lib/ia32) - list(APPEND TBB_LIB_SEARCH_PATH ${dir}/lib/ia32/${prefix}) - list(APPEND TBB_LIB_SEARCH_PATH ${dir}/ia32/lib) - list(APPEND TBB_LIB_SEARCH_PATH ${dir}/ia32/${prefix}/lib) - endif () - endforeach() -endforeach () - -# add general search paths -foreach (dir IN LISTS TBB_PREFIX_PATH) - list(APPEND TBB_LIB_SEARCH_PATH ${dir}/lib ${dir}/Lib ${dir}/lib/tbb - ${dir}/Libs) - list(APPEND TBB_INC_SEARCH_PATH ${dir}/include ${dir}/Include - ${dir}/include/tbb) -endforeach () - -set(TBB_LIBRARY_NAMES tbb) -get_debug_names(TBB_LIBRARY_NAMES) - -find_path(TBB_INCLUDE_DIR - NAMES tbb/tbb.h - PATHS ${TBB_INC_SEARCH_PATH}) - -find_library(TBB_LIBRARY_RELEASE - NAMES ${TBB_LIBRARY_NAMES} - PATHS ${TBB_LIB_SEARCH_PATH}) -find_library(TBB_LIBRARY_DEBUG - NAMES ${TBB_LIBRARY_NAMES_DEBUG} - PATHS ${TBB_LIB_SEARCH_PATH}) -make_library_set(TBB_LIBRARY) - -findpkg_finish(TBB tbb) - -#if we haven't found TBB no point on going any further -if (NOT TBB_FOUND) - return() -endif () - -#============================================================================= -# Look for TBB's malloc package -set(TBB_MALLOC_LIBRARY_NAMES tbbmalloc) -get_debug_names(TBB_MALLOC_LIBRARY_NAMES) - -find_path(TBB_MALLOC_INCLUDE_DIR - NAMES tbb/tbb.h - PATHS ${TBB_INC_SEARCH_PATH}) - -find_library(TBB_MALLOC_LIBRARY_RELEASE - NAMES ${TBB_MALLOC_LIBRARY_NAMES} - PATHS ${TBB_LIB_SEARCH_PATH}) -find_library(TBB_MALLOC_LIBRARY_DEBUG - NAMES ${TBB_MALLOC_LIBRARY_NAMES_DEBUG} - PATHS ${TBB_LIB_SEARCH_PATH}) -make_library_set(TBB_MALLOC_LIBRARY) - -findpkg_finish(TBB_MALLOC tbbmalloc) - -#============================================================================= -# Look for TBB's malloc proxy package -set(TBB_MALLOC_PROXY_LIBRARY_NAMES tbbmalloc_proxy) -get_debug_names(TBB_MALLOC_PROXY_LIBRARY_NAMES) - -find_path(TBB_MALLOC_PROXY_INCLUDE_DIR - NAMES tbb/tbbmalloc_proxy.h - PATHS ${TBB_INC_SEARCH_PATH}) - -find_library(TBB_MALLOC_PROXY_LIBRARY_RELEASE - NAMES ${TBB_MALLOC_PROXY_LIBRARY_NAMES} - PATHS ${TBB_LIB_SEARCH_PATH}) -find_library(TBB_MALLOC_PROXY_LIBRARY_DEBUG - NAMES ${TBB_MALLOC_PROXY_LIBRARY_NAMES_DEBUG} - PATHS ${TBB_LIB_SEARCH_PATH}) -make_library_set(TBB_MALLOC_PROXY_LIBRARY) - -findpkg_finish(TBB_MALLOC_PROXY tbbmalloc_proxy) - - -#============================================================================= -# Parse all the version numbers from tbb. -if(NOT TBB_VERSION) - if(EXISTS "${TBB_INCLUDE_DIR}/tbb/version.h") - # The newer oneTBB provides tbb/version.h but no tbb/tbb_stddef.h. - set(version_file "${TBB_INCLUDE_DIR}/tbb/version.h") - else() - # Older TBB provides tbb/tbb_stddef.h but no tbb/version.h. - set(version_file "${TBB_INCLUDE_DIR}/tbb/tbb_stddef.h") - endif() - - file(STRINGS - "${version_file}" - TBB_VERSION_CONTENTS - REGEX "VERSION") - - string(REGEX REPLACE - ".*#define TBB_VERSION_MAJOR ([0-9]+).*" "\\1" - TBB_VERSION_MAJOR "${TBB_VERSION_CONTENTS}") - - string(REGEX REPLACE - ".*#define TBB_VERSION_MINOR ([0-9]+).*" "\\1" - TBB_VERSION_MINOR "${TBB_VERSION_CONTENTS}") - - string(REGEX REPLACE - ".*#define TBB_INTERFACE_VERSION ([0-9]+).*" "\\1" - TBB_INTERFACE_VERSION "${TBB_VERSION_CONTENTS}") - - string(REGEX REPLACE - ".*#define TBB_COMPATIBLE_INTERFACE_VERSION ([0-9]+).*" "\\1" - TBB_COMPATIBLE_INTERFACE_VERSION "${TBB_VERSION_CONTENTS}") - - set(TBB_VERSION "${TBB_VERSION_MAJOR}.${TBB_VERSION_MINOR}") -endif() diff --git a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/thrust/cmake/README.md b/IfcPlusPlus/src/external/manifold/src/third_party/thrust/thrust/cmake/README.md deleted file mode 100644 index c85a8c857..000000000 --- a/IfcPlusPlus/src/external/manifold/src/third_party/thrust/thrust/cmake/README.md +++ /dev/null @@ -1,215 +0,0 @@ -# Using Thrust with CMake - -Thrust provides configuration files that simplify using Thrust -from other CMake projects. Requirements: - -- Thrust >= 1.9.10 -- CMake >= 3.15 - -See the [Fixing Legacy FindThrust.cmake](#fixing-legacy-findthrustcmake) -section for solutions that work on older Thrust versions. - -## User Guide - -#### Default Configuration (CUDA) - -Thrust is configured using a `thrust_create_target` CMake function that -assembles a complete interface to the Thrust library: - -```cmake -find_package(Thrust REQUIRED CONFIG) -thrust_create_target(Thrust) -target_link_libraries(MyProgram Thrust) -``` - -The first argument is the name of the interface target to create, and any -additional options will be used to configure the target. By default, -`thrust_create_target` will configure its result to use CUDA acceleration. - -If desired, `thrust_create_target` may be called multiple times to build -several unique Thrust interface targets with different configurations, as -detailed below. - -**Note:** If CMake is unable to locate Thrust, specify the path to Thrust's CMake -configuration directory (where this README file is located) as `Thrust_DIR`. -If cloning Thrust from github, this would be - -``` -$ cmake . -DThrust_DIR=/thrust/cmake/ -``` - -#### TBB / OpenMP - -To explicitly specify host/device systems, `HOST` and `DEVICE` arguments can be -passed to `thrust_create_target`. If an explicit system is not specified, the -target will default to using CPP for host and/or CUDA for device. - -```cmake -thrust_create_target(ThrustTBB DEVICE TBB) -thrust_create_target(ThrustOMP HOST CPP DEVICE OMP) -``` - -will create targets `ThrustTBB` and `ThrustOMP`. Both will use the serial `CPP` -host system, but will find and use TBB or OpenMP for the device system. - -#### Configure Target from Cache Options - -To allow a Thrust target to be configurable easily via `cmake-gui` or -`ccmake`, pass the `FROM_OPTIONS` flag to `thrust_create_target`. This will add -`THRUST_HOST_SYSTEM` and `THRUST_DEVICE_SYSTEM` options to the CMake cache that -allow selection from the systems supported by this version of Thrust. - -```cmake -thrust_create_target(Thrust FROM_OPTIONS - [HOST_OPTION