├── src ├── CMakeLists.txt ├── main.cpp ├── union_find_set.h ├── common.h ├── tool.cpp ├── grid.h ├── plane.cpp ├── tr.h ├── my_gmp.h ├── io.cpp ├── check.cpp ├── my_gmp.cpp ├── triangulate.cpp ├── seq.h └── grid.cpp ├── README.md ├── example ├── simplecase.obj ├── stair.obj └── eight.obj ├── CMakeLists.txt ├── run.sh ├── LICENSE └── cmake └── FindEigen.cmake /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | aux_source_directory(. src) 2 | 3 | find_package(Boost COMPONENTS program_options REQUIRED) 4 | include_directories(${Boost_INCLUDE_DIRS}) 5 | 6 | find_package(Eigen REQUIRED) 7 | include_directories(${EIGEN_INCLUDE_DIR}) 8 | 9 | 10 | add_executable(topocut ${src}) 11 | target_link_libraries(topocut 12 | ${Boost_LIBRARIES} 13 | gmpxx 14 | gmp 15 | ) 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TopoCut 2 | This is the Open Source Code for SIGGRAPH 2022 Technical Paper 3 | "TopoCut: Fast and Robust Planar Cutting of Arbitrary Domains" 4 | 5 | 6 | Author: Xianzhong Fang 7 | 8 | Email: xzfangcs [at] 163 [dot] com 9 | 10 | 11 | Compilation Environment: Linux, such as Ubuntu 20.04. 12 | 13 | ## Install Third Libraries in Linux 14 | ```console 15 | $ sudo apt install libeigen3-dev libboost-program-options-dev libgmp-dev libcgal-dev 16 | ``` 17 | 18 | ## Compile in Linux 19 | 20 | ```console 21 | $ mkdir build 22 | $ cd ./build 23 | $ cmake .. -DCMAKE_BUILD_TYPE=Release 24 | ``` 25 | 26 | ## A simple test 27 | 28 | ```console 29 | $ bash run.sh 30 | ``` 31 | -------------------------------------------------------------------------------- /example/simplecase.obj: -------------------------------------------------------------------------------- 1 | v 75.000000 100.000000 0.000000 2 | v 100.000000 -0.000000 10.000000 3 | v 100.000000 -0.000000 0.000000 4 | v 75.000000 100.000000 10.000000 5 | v 0.000000 0.000000 10.000000 6 | v 0.000000 0.000000 -0.000000 7 | v 25.000000 50.000000 0.000000 8 | v 75.000000 50.000000 0.000000 9 | v 75.000000 50.000000 10.000000 10 | v 25.000000 100.000000 10.000000 11 | v 25.000000 100.000000 -0.000000 12 | v 25.000000 50.000000 10.000000 13 | f 1 2 3 14 | f 1 4 2 15 | f 2 5 3 16 | f 5 6 3 17 | f 6 7 3 18 | f 7 8 3 19 | f 8 1 3 20 | f 4 9 2 21 | f 9 5 2 22 | f 5 10 6 23 | f 10 11 6 24 | f 11 7 6 25 | f 9 12 5 26 | f 12 10 5 27 | f 12 9 7 28 | f 9 8 7 29 | f 11 12 7 30 | f 9 4 8 31 | f 4 1 8 32 | f 11 10 12 33 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | project(TopoCut) 3 | 4 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) 5 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) 6 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 7 | 8 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} 9 | ${CMAKE_SOURCE_DIR}/cmake) 10 | 11 | set(CMAKE_CXX_FLAGS "-Wall -std=c++17 -frounding-math") 12 | 13 | find_package(OpenMP) 14 | if(OPENMP_FOUND) 15 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") 16 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") 17 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}") 18 | message("-- FIND OPENMP") 19 | message("-- ${CMAKE_CXX_FLAGS}") 20 | endif(OPENMP_FOUND) 21 | 22 | add_subdirectory(src) 23 | -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | cd `dirname $0` 4 | cur_dir=`pwd` 5 | 6 | ## input directory 7 | in_dir=${cur_dir}/example 8 | 9 | ## output directory 10 | tmpdir=./tmpdir 11 | build_dir=${tmpdir}/build 12 | ## the executable file 13 | exe=${build_dir}/bin/topocut 14 | 15 | if [ ! -f ${exe} ] ; then 16 | #sudo apt install libeigen3-dev libboost-program-options-dev libgmp-dev libcgal-dev 17 | mkdir -p ${build_dir} 18 | cd ${build_dir} 19 | cmake ${cur_dir} -DCMAKE_BUILD_TYPE=Release 20 | make -j5 21 | cd - 22 | fi 23 | 24 | ### set mesh name 25 | #mesh=eight 26 | mesh=cylinder 27 | 28 | ## set output dir 29 | out_dir=${tmpdir}/output 30 | out_mesh_dir=${out_dir}/${mesh} 31 | mkdir -p ${out_mesh_dir} 32 | 33 | ## output files 34 | obj=${in_dir}/${mesh}.obj 35 | plane=${out_mesh_dir}/${mesh}.plane 36 | cut_mesh=${out_mesh_dir}/${mesh}.cm.vtk 37 | 38 | 39 | 40 | #### Generate cut planes 41 | ## axis-aligned cuts 42 | ${exe} plane -i ${obj} -o ${plane} -s bound_box_xyz --nx 5 --ny 5 --nz 5 43 | ## or use random cuts 44 | #${exe} plane -i ${obj} -o ${plane} -s random -P 10 45 | 46 | ## Generate cut-mesh by using cut-planes 47 | ${exe} cut -i ${obj} -p ${plane} -o ${cut_mesh} --is-triangulate 0 48 | 49 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2022, Xianzhong Fang 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of TopoCut (TopoCut: Fast and Robust Planar Cutting of Arbitrary Domains) 3 | 4 | Copyright (C) 2022, Xianzhong Fang 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | * Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | Author: Xianzhong Fang, Email: xzfangcs@163.com 33 | */ 34 | 35 | 36 | #include 37 | #include 38 | #include 39 | #include "grid.h" 40 | #include "common.h" 41 | 42 | namespace fxz { 43 | namespace grid { 44 | // transform all triangles in polyhedral mesh into ply 45 | int polyvtk_to_ply(int argc, char* argv[]); 46 | } 47 | } // fxz 48 | 49 | int main(int argc, char* argv[]) 50 | { 51 | if (argc == 1) { 52 | std::cout << " There is no any parameter." << std::endl; 53 | std::cout << "# sub-program: plane, cut" << std::endl; 54 | return 0; 55 | 56 | } else if (argc > 1) { 57 | 58 | std::string prog = argv[1]; 59 | std::cout << "# main prog: \n" << argv[0] << std::endl; 60 | std::cout << "# sub prog: " << argv[1] << std::endl; 61 | 62 | CALL_SUBPROG("plane", fxz::grid::make_cut_plane); 63 | CALL_SUBPROG("cut", fxz::grid::general_exact_cut); 64 | CALL_SUBPROG("check", fxz::grid::check_input); 65 | CALL_SUBPROG("poly2ply", fxz::grid::polyvtk_to_ply); 66 | } 67 | 68 | return 0; 69 | } 70 | -------------------------------------------------------------------------------- /src/union_find_set.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of TopoCut (TopoCut: Fast and Robust Planar Cutting of Arbitrary Domains) 3 | 4 | Copyright (C) 2022, Xianzhong Fang 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | * Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | Author: Xianzhong Fang, Email: xzfangcs@163.com 33 | */ 34 | 35 | 36 | #ifndef UNION_FIND_SET_H 37 | #define UNION_FIND_SET_H 38 | 39 | #include 40 | 41 | 42 | namespace fxz { 43 | 44 | class union_find_set 45 | { 46 | public: 47 | union_find_set() { n_=0;} 48 | union_find_set(size_t n):n_(n) { parent_.resize(n_, n_+5);} 49 | ~union_find_set() { } 50 | 51 | size_t find(size_t a) 52 | { 53 | assert(an_)?a:(parent_[a]=find(parent_[a])); 55 | } 56 | 57 | void set_union(size_t a, size_t b) 58 | { 59 | assert(a parent_; 88 | }; 89 | 90 | } // namespace fxz 91 | 92 | 93 | #endif 94 | -------------------------------------------------------------------------------- /cmake/FindEigen.cmake: -------------------------------------------------------------------------------- 1 | # - Try to find Eigen3 lib 2 | # 3 | # This module supports requiring a minimum version, e.g. you can do 4 | # find_package(Eigen3 3.1.2) 5 | # to require version 3.1.2 or newer of Eigen3. 6 | # 7 | # Once done this will define 8 | # 9 | # EIGEN_FOUND - system has eigen lib with correct version 10 | # EIGEN_INCLUDE_DIR - the eigen include directory 11 | # EIGEN_VERSION - eigen version 12 | 13 | # Copyright (c) 2006, 2007 Montel Laurent, 14 | # Copyright (c) 2008, 2009 Gael Guennebaud, 15 | # Copyright (c) 2009 Benoit Jacob 16 | # Redistribution and use is allowed according to the terms of the 2-clause BSD license. 17 | 18 | if(NOT Eigen_FIND_VERSION) 19 | if(NOT Eigen_FIND_VERSION_MAJOR) 20 | set(Eigen_FIND_VERSION_MAJOR 2) 21 | endif(NOT Eigen_FIND_VERSION_MAJOR) 22 | if(NOT Eigen_FIND_VERSION_MINOR) 23 | set(Eigen_FIND_VERSION_MINOR 91) 24 | endif(NOT Eigen_FIND_VERSION_MINOR) 25 | if(NOT Eigen_FIND_VERSION_PATCH) 26 | set(Eigen_FIND_VERSION_PATCH 0) 27 | endif(NOT Eigen_FIND_VERSION_PATCH) 28 | 29 | set(Eigen_FIND_VERSION "${Eigen_FIND_VERSION_MAJOR}.${Eigen_FIND_VERSION_MINOR}.${Eigen_FIND_VERSION_PATCH}") 30 | endif(NOT Eigen_FIND_VERSION) 31 | 32 | macro(_eigen3_check_version) 33 | file(READ "${EIGEN_INCLUDE_DIR}/Eigen/src/Core/util/Macros.h" _eigen3_version_header) 34 | 35 | string(REGEX MATCH "define[ \t]+EIGEN_WORLD_VERSION[ \t]+([0-9]+)" _eigen3_world_version_match "${_eigen3_version_header}") 36 | set(EIGEN_WORLD_VERSION "${CMAKE_MATCH_1}") 37 | string(REGEX MATCH "define[ \t]+EIGEN_MAJOR_VERSION[ \t]+([0-9]+)" _eigen3_major_version_match "${_eigen3_version_header}") 38 | set(EIGEN_MAJOR_VERSION "${CMAKE_MATCH_1}") 39 | string(REGEX MATCH "define[ \t]+EIGEN_MINOR_VERSION[ \t]+([0-9]+)" _eigen3_minor_version_match "${_eigen3_version_header}") 40 | set(EIGEN_MINOR_VERSION "${CMAKE_MATCH_1}") 41 | 42 | set(EIGEN_VERSION ${EIGEN_WORLD_VERSION}.${EIGEN_MAJOR_VERSION}.${EIGEN_MINOR_VERSION}) 43 | if(${EIGEN_VERSION} VERSION_LESS ${Eigen_FIND_VERSION}) 44 | set(EIGEN_VERSION_OK FALSE) 45 | else(${EIGEN_VERSION} VERSION_LESS ${Eigen_FIND_VERSION}) 46 | set(EIGEN_VERSION_OK TRUE) 47 | endif(${EIGEN_VERSION} VERSION_LESS ${Eigen_FIND_VERSION}) 48 | 49 | if(NOT EIGEN_VERSION_OK) 50 | 51 | message(STATUS "Eigen version ${EIGEN_VERSION} found in ${EIGEN_INCLUDE_DIR}, " 52 | "but at least version ${Eigen_FIND_VERSION} is required") 53 | endif(NOT EIGEN_VERSION_OK) 54 | endmacro(_eigen3_check_version) 55 | 56 | if (EIGEN_INCLUDE_DIRS) 57 | 58 | # in cache already 59 | _eigen3_check_version() 60 | set(EIGEN_FOUND ${EIGEN_VERSION_OK}) 61 | 62 | else () 63 | 64 | find_path(EIGEN_INCLUDE_DIR NAMES signature_of_eigen3_matrix_library 65 | PATHS 66 | ${CMAKE_INSTALL_PREFIX}/include 67 | ${KDE4_INCLUDE_DIR} 68 | "/usr/include" 69 | PATH_SUFFIXES eigen3 eigen 70 | ) 71 | 72 | if(EIGEN_INCLUDE_DIR) 73 | _eigen3_check_version() 74 | endif(EIGEN_INCLUDE_DIR) 75 | 76 | include(FindPackageHandleStandardArgs) 77 | find_package_handle_standard_args(Eigen DEFAULT_MSG EIGEN_INCLUDE_DIR EIGEN_VERSION_OK) 78 | 79 | mark_as_advanced(EIGEN_INCLUDE_DIR) 80 | SET(EIGEN_INCLUDE_DIRS ${EIGEN_INCLUDE_DIR} CACHE PATH "The Eigen include path.") 81 | 82 | endif() 83 | 84 | -------------------------------------------------------------------------------- /src/common.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of TopoCut (TopoCut: Fast and Robust Planar Cutting of Arbitrary Domains) 3 | 4 | Copyright (C) 2022, Xianzhong Fang 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | * Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | Author: Xianzhong Fang, Email: xzfangcs@163.com 33 | */ 34 | 35 | 36 | #ifndef COMMON_FXZ_H 37 | #define COMMON_FXZ_H 38 | #include 39 | #include 40 | #include 41 | 42 | namespace fxz { 43 | 44 | const size_t INVALID_NUM = (size_t)(-1); 45 | const size_t UNSIGN_NEG_ONE = (size_t)(-1); 46 | const double kPI = 3.14159265; 47 | 48 | #define CALL_FUNC(pn) { \ 49 | if(pn){ return __LINE__; }} 50 | 51 | 52 | #define CALL_FUNC_WITH_CLOCK(pn, func_name) { \ 53 | auto start = std::chrono::high_resolution_clock::now(); \ 54 | if (pn) { std::cerr << "# [ ERROR ] " << #pn << std::endl; return __LINE__; } \ 55 | auto end = std::chrono::high_resolution_clock::now(); \ 56 | double time_taken=std::chrono::duration_cast(end - start).count(); \ 57 | time_taken *= 1e-9; \ 58 | std::cout << "--- Time taken by program " << func_name << " : " << std::fixed \ 59 | << time_taken << std::setprecision(9) << " sec" << std::endl; \ 60 | } 61 | 62 | 63 | #define CALL_SUBPROG(sp, func) {if (prog==sp) {CALL_FUNC(func(argc,argv));}} 64 | 65 | #define FASSERT(func) {if(!(func)){ \ 66 | std::cerr<<"# [ ERROR ] " << " L" \ 67 | << __LINE__ << ": assert "<<#func< 78 | 79 | namespace fxz { 80 | namespace eigen { 81 | typedef Eigen::Matrix ematrixd; 82 | typedef Eigen::Matrix evecd; 83 | typedef Eigen::Matrix evec3d; 84 | typedef Eigen::Map cmap_ematrixd; 85 | typedef Eigen::Map map_evec3d; 86 | typedef Eigen::Map cmap_evecd; 87 | typedef Eigen::Map cmap_evec3d; 88 | } // namespace eigen 89 | } // namespace fxz 90 | 91 | 92 | #endif 93 | -------------------------------------------------------------------------------- /src/tool.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of TopoCut (TopoCut: Fast and Robust Planar Cutting of Arbitrary Domains) 3 | 4 | Copyright (C) 2022, Xianzhong Fang 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | * Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | Author: Xianzhong Fang, Email: xzfangcs@163.com 33 | */ 34 | 35 | 36 | 37 | #include "common.h" 38 | #include "grid.h" 39 | 40 | 41 | namespace fxz { 42 | namespace grid { 43 | 44 | int write_ply( 45 | const std::string& out_file, 46 | const std::vector& V, 47 | const std::vector& M); 48 | 49 | 50 | int read_poly_vtk( 51 | const std::string& in_poly, 52 | std::vector& V, 53 | std::vector& C, size_t& cell_num); 54 | 55 | 56 | int polyvtk_to_ply( 57 | const std::string& in_poly, const std::string& out_ply) 58 | { 59 | 60 | std::vector V; 61 | std::vector C; 62 | size_t cell_num(0); 63 | if (read_poly_vtk(in_poly, V, C, cell_num)) {return 1;} 64 | 65 | std::set > tris; 66 | 67 | size_t id=0; 68 | for (size_t ci = 0; ci < cell_num; ++ci) { 69 | //size_t cell_size = C[id]; 70 | ++id; 71 | size_t fn = C[id]; 72 | ++id; 73 | for (size_t fi = 0; fi < fn; ++fi) { 74 | size_t f_vn = C[id]; 75 | std::vector f_vs; 76 | f_vs.reserve(3); 77 | ++id; 78 | for (size_t vi = 0; vi < f_vn; ++vi) { 79 | f_vs.push_back(C[id+vi]); 80 | } 81 | id+=f_vn; 82 | if (f_vn != 3) { 83 | std::cerr << "# [ ERROR ] the polyhedral mesh has non triangle face." << std::endl; 84 | return 1; 85 | } 86 | std::sort(f_vs.begin(), f_vs.end()); 87 | tris.insert(std::make_tuple(f_vs[0], f_vs[1], f_vs[2])); 88 | } 89 | } 90 | 91 | std::vector all_tris; 92 | all_tris.reserve(tris.size()*3); 93 | for (auto& t : tris) { 94 | all_tris.push_back(std::get<0>(t)); 95 | all_tris.push_back(std::get<1>(t)); 96 | all_tris.push_back(std::get<2>(t)); 97 | } 98 | 99 | std::cout << "-- start to write ply ..." << std::endl; 100 | if (write_ply(out_ply, V, all_tris)) {return 1;} 101 | std::cout << "-- write into file: " << out_ply << std::endl; 102 | 103 | return 0; 104 | } 105 | 106 | 107 | int polyvtk_to_ply(const pm_map& para) 108 | { 109 | const std::string& in_poly = para["input"].as(); 110 | const std::string& out_ply = para["output"].as(); 111 | 112 | return polyvtk_to_ply(in_poly, out_ply); 113 | } 114 | 115 | int polyvtk_to_ply(int argc, char* argv[]) 116 | { 117 | using namespace boost::program_options; 118 | 119 | try { 120 | options_description console_desc("TopoCut Console: transform polyhedral mesh (vtk) into triangles as ply format"); 121 | console_desc.add_options() 122 | ("help,h", "help screen") 123 | ("input,i", value()->notifier(on_input), "the input polyhedral vtk") 124 | ("output,o", value()->notifier(on_output), "the output triangles ply"); 125 | 126 | fxz::grid::pm_map vm; 127 | store(parse_command_line(argc, argv, console_desc), vm); 128 | notify(vm); 129 | if (vm.count("help")) { std::cout << console_desc << std::endl; } 130 | else { 131 | CALL_FUNC(fxz::grid::polyvtk_to_ply(vm)); 132 | } 133 | } catch (const error &ex) { 134 | std::cerr << ex.what() << std::endl; 135 | } 136 | 137 | return 0; 138 | } 139 | 140 | 141 | 142 | } // grid 143 | } // fxz 144 | 145 | -------------------------------------------------------------------------------- /example/stair.obj: -------------------------------------------------------------------------------- 1 | # Blender v2.82 (sub 7) OBJ File: '' 2 | # www.blender.org 3 | o square10.001 4 | v 0.000000 0.000000 0.000000 5 | v 0.000000 -0.000000 1.000000 6 | v 1.000000 -0.000000 1.000000 7 | v 1.000000 0.000000 0.000000 8 | v 2.000000 -0.000000 1.000000 9 | v 0.000000 -0.000000 2.000000 10 | v 6.000000 4.428771 10.000000 11 | v 2.000000 -0.000000 2.000000 12 | v 3.000000 -0.000000 2.000000 13 | v 0.000000 -0.000000 3.000000 14 | v 5.000000 4.428771 10.000000 15 | v 3.000000 4.428771 10.000000 16 | v 3.000000 -0.000000 3.000000 17 | v 4.000000 -0.000000 3.000000 18 | v 0.000000 -0.000000 4.000000 19 | v 4.000000 4.428771 10.000000 20 | v 1.000000 4.428771 10.000000 21 | v 9.000000 4.428771 9.000000 22 | v 4.000000 -0.000000 4.000000 23 | v 5.000000 -0.000000 4.000000 24 | v 0.000000 -0.000000 5.000000 25 | v 2.000000 4.428771 10.000000 26 | v 10.000000 4.428771 9.000000 27 | v 8.000000 4.428771 8.000000 28 | v 0.000000 4.428771 7.000000 29 | v 5.000000 -0.000000 5.000000 30 | v 6.000000 -0.000000 5.000000 31 | v 0.000000 -0.000000 6.000000 32 | v 0.000000 4.428771 10.000000 33 | v 9.000000 4.428771 8.000000 34 | v 7.000000 4.428771 7.000000 35 | v 6.000000 4.428772 5.000000 36 | v 4.000000 4.428772 4.000000 37 | v 6.000000 -0.000000 6.000000 38 | v 7.000000 -0.000000 6.000000 39 | v 10.000000 4.428771 10.000000 40 | v 0.000000 -0.000000 7.000000 41 | v 0.000000 4.428771 9.000000 42 | v 8.000000 4.428771 7.000000 43 | v 0.000000 4.428771 6.000000 44 | v 5.000000 4.428772 4.000000 45 | v 3.000000 4.428772 3.000000 46 | v 2.000000 4.428772 2.000000 47 | v 7.000000 -0.000000 7.000000 48 | v 8.000000 -0.000000 7.000000 49 | v 9.000000 4.428771 10.000000 50 | v 8.000000 4.428771 10.000000 51 | v 0.000000 -0.000000 8.000000 52 | v 0.000000 4.428771 8.000000 53 | v 6.000000 4.428771 6.000000 54 | v 0.000000 4.428772 5.000000 55 | v 4.000000 4.428772 3.000000 56 | v 3.000000 4.428772 2.000000 57 | v 2.000000 4.428772 1.000000 58 | v 0.000000 4.428772 1.000000 59 | v 8.000000 -0.000000 8.000000 60 | v 9.000000 -0.000000 8.000000 61 | v 7.000000 4.428771 10.000000 62 | v 0.000000 -0.000000 9.000000 63 | v 7.000000 4.428771 6.000000 64 | v 5.000000 4.428772 5.000000 65 | v 0.000000 4.428772 4.000000 66 | v 0.000000 4.428772 3.000000 67 | v 0.000000 4.428772 2.000000 68 | v 1.000000 4.428772 1.000000 69 | v 1.000000 4.428772 0.000000 70 | v 0.000000 4.428772 0.000000 71 | v 9.000000 -0.000000 9.000000 72 | v 10.000000 -0.000000 9.000000 73 | v 0.000000 -0.000000 10.000000 74 | v 1.000000 -0.000000 10.000000 75 | v 2.000000 -0.000000 10.000000 76 | v 3.000000 -0.000000 10.000000 77 | v 4.000000 -0.000000 10.000000 78 | v 5.000000 -0.000000 10.000000 79 | v 6.000000 -0.000000 10.000000 80 | v 7.000000 -0.000000 10.000000 81 | v 8.000000 -0.000000 10.000000 82 | v 9.000000 -0.000000 10.000000 83 | v 10.000000 -0.000000 10.000000 84 | s off 85 | f 33 51 40 86 | f 13 52 14 87 | f 75 16 74 88 | f 8 53 9 89 | f 26 32 27 90 | f 21 62 15 91 | f 35 31 44 92 | f 3 54 5 93 | f 48 49 25 94 | f 71 17 29 95 | f 33 42 51 96 | f 58 31 7 97 | f 28 51 21 98 | f 48 25 37 99 | f 78 58 77 100 | f 79 47 78 101 | f 9 42 13 102 | f 35 60 31 103 | f 6 64 55 104 | f 20 41 61 105 | f 11 7 31 106 | f 31 50 11 107 | f 61 41 33 108 | f 10 64 6 109 | f 72 17 71 110 | f 59 49 48 111 | f 26 61 32 112 | f 44 31 39 113 | f 5 54 43 114 | f 37 25 40 115 | f 24 47 18 116 | f 47 46 18 117 | f 33 52 42 118 | f 68 18 23 119 | f 4 65 3 120 | f 75 11 16 121 | f 59 38 49 122 | f 19 33 41 123 | f 1 67 66 124 | f 55 64 65 125 | f 18 30 24 126 | f 24 39 31 127 | f 65 66 67 128 | f 70 29 38 129 | f 72 22 17 130 | f 9 53 42 131 | f 57 30 18 132 | f 34 50 60 133 | f 64 63 43 134 | f 50 32 61 135 | f 43 54 65 136 | f 65 67 55 137 | f 74 16 12 138 | f 69 23 36 139 | f 10 63 64 140 | f 44 39 45 141 | f 14 52 33 142 | f 27 32 50 143 | f 31 60 50 144 | f 36 23 18 145 | f 76 7 11 146 | f 77 58 7 147 | f 56 24 30 148 | f 4 66 65 149 | f 8 43 53 150 | f 80 46 79 151 | f 71 29 70 152 | f 42 53 43 153 | f 58 47 24 154 | f 46 36 18 155 | f 73 12 22 156 | f 15 62 63 157 | f 80 36 46 158 | f 21 51 62 159 | f 6 55 2 160 | f 2 67 1 161 | f 45 24 56 162 | f 57 18 68 163 | f 24 31 58 164 | f 12 61 25 165 | f 45 39 24 166 | f 2 55 67 167 | f 3 65 54 168 | f 69 36 80 169 | f 19 41 20 170 | f 56 30 57 171 | f 20 61 26 172 | f 5 43 8 173 | f 15 63 10 174 | f 42 43 62 175 | f 79 46 47 176 | f 78 47 58 177 | f 13 42 52 178 | f 73 22 72 179 | f 14 33 19 180 | f 70 38 59 181 | f 68 23 69 182 | f 34 60 35 183 | f 12 16 61 184 | f 61 33 40 185 | f 28 40 51 186 | f 74 12 73 187 | f 37 40 28 188 | f 1 66 4 189 | f 77 7 76 190 | f 76 11 75 191 | f 27 50 34 192 | f 38 17 49 193 | f 50 16 11 194 | f 50 61 16 195 | f 13 21 15 196 | f 17 22 49 197 | f 22 12 25 198 | f 25 61 40 199 | f 43 65 64 200 | f 38 29 17 201 | f 49 22 25 202 | f 62 51 42 203 | f 43 63 62 204 | f 1 4 3 205 | f 3 5 8 206 | f 8 9 13 207 | f 13 14 19 208 | f 19 20 26 209 | f 26 27 34 210 | f 34 35 44 211 | f 44 45 56 212 | f 56 57 68 213 | f 68 69 80 214 | f 79 78 68 215 | f 78 77 56 216 | f 68 80 79 217 | f 34 44 75 218 | f 44 56 77 219 | f 56 68 78 220 | f 77 76 44 221 | f 76 75 44 222 | f 19 26 28 223 | f 26 34 74 224 | f 74 34 75 225 | f 74 73 26 226 | f 26 73 37 227 | f 8 13 15 228 | f 13 19 21 229 | f 21 19 28 230 | f 73 72 37 231 | f 72 71 48 232 | f 1 3 2 233 | f 3 8 6 234 | f 2 3 6 235 | f 26 37 28 236 | f 71 70 59 237 | f 15 10 8 238 | f 10 6 8 239 | f 72 48 37 240 | f 71 59 48 241 | -------------------------------------------------------------------------------- /src/grid.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of TopoCut (TopoCut: Fast and Robust Planar Cutting of Arbitrary Domains) 3 | 4 | Copyright (C) 2022, Xianzhong Fang 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | * Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | Author: Xianzhong Fang, Email: xzfangcs@163.com 33 | */ 34 | 35 | 36 | #ifndef GRID_FXZ_H 37 | #define GRID_FXZ_H 38 | 39 | #include 40 | #include 41 | #include "seq.h" 42 | 43 | namespace fxz { 44 | namespace grid { 45 | 46 | typedef boost::program_options::variables_map pm_map; 47 | 48 | int make_cut_plane(const pm_map& para); 49 | int make_cut_plane(int argc, char* argv[]); 50 | 51 | double ave_edge_length( 52 | const std::vector& V, 53 | const std::map, std::vector >& e2f); 54 | 55 | int check_plane( 56 | const std::vector& P, const double norm_eps, const double len_eps, 57 | std::vector& repeated_p); 58 | 59 | int check_delete_repeated_plane( 60 | std::vector& P, const double eps); 61 | 62 | int general_exact_cut(const pm_map& para); 63 | int general_exact_cut(int argc, char* argv[]); 64 | 65 | int general_exact_cut( 66 | const pm_map& para, 67 | const std::string& out_file, 68 | const std::vector& V, 69 | const std::vector& M, 70 | std::vector& P, 71 | std::vector& CV, 72 | std::vector& CC, size_t& cn, 73 | std::vector& new_CV, double& sum_vol); 74 | 75 | int triangulate_cut_mesh( 76 | const std::string& out_ply, 77 | size_t ori_vn, double all_vol, 78 | const std::vector& V, 79 | const std::vector& C, 80 | size_t cn); 81 | 82 | 83 | int read_mesh( 84 | const std::string& in_mesh, 85 | std::vector& V, 86 | std::vector& M); 87 | 88 | int read_vector( 89 | const std::string& file, 90 | std::vector& P); 91 | 92 | int write_obj( 93 | const std::vector& V, 94 | const std::vector >& M, 95 | const std::string& out_file); 96 | 97 | 98 | int write_ply( 99 | const std::vector& V, 100 | const std::vector >& M, 101 | const std::string& out_file); 102 | 103 | 104 | int write_vector( 105 | const std::vector& P, size_t nc, 106 | const std::string& file); 107 | 108 | int write_cutcell_to_vtk( 109 | const std::string& file, 110 | const std::vector& CV, 111 | const std::vector& CC, size_t cell_num); 112 | 113 | 114 | int build_edge_to_triangle_map( 115 | const std::vector& M, 116 | std::map, std::vector >& e2f); 117 | 118 | int check_input(const pm_map& para); 119 | int check_input(int argc, char* argv[]); 120 | 121 | int check_degenerated_triangle( 122 | const std::vector& V, 123 | const std::vector& M, const double eps); 124 | 125 | int check_volume( 126 | const std::vector& V, 127 | const std::vector& M, const double eps, double& sum_vol); 128 | 129 | double check_volume( 130 | const std::vector& V, 131 | const std::vector& M); 132 | 133 | 134 | int check_topology( 135 | const std::vector& M, 136 | const std::map, std::vector >& e2f); 137 | 138 | int check_topology(const std::vector& M); 139 | 140 | 141 | 142 | inline void on_input(const std::string& str) 143 | { 144 | std::cout << "Input mesh: " << str << std::endl; 145 | } 146 | 147 | inline void on_output(const std::string& str) 148 | { 149 | std::cout << "Ouput mesh: " << str << std::endl; 150 | } 151 | 152 | inline void on_plane(const std::string& str) 153 | { 154 | std::cout << "Input plane: " << str << std::endl; 155 | } 156 | 157 | int generate_cut_cells( 158 | const pm_map& para, 159 | const sequence_type& seq, const std::string& out_file, 160 | std::vector& CC, size_t& cn, 161 | std::vector& new_CV, 162 | std::vector >& face_triangles); 163 | 164 | } // 165 | } // fxz 166 | 167 | 168 | #endif 169 | 170 | -------------------------------------------------------------------------------- /src/plane.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of TopoCut (TopoCut: Fast and Robust Planar Cutting of Arbitrary Domains) 3 | 4 | Copyright (C) 2022, Xianzhong Fang 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | * Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | Author: Xianzhong Fang, Email: xzfangcs@163.com 33 | */ 34 | 35 | 36 | #include 37 | #include 38 | 39 | #include "common.h" 40 | #include "grid.h" 41 | 42 | 43 | using namespace boost::program_options; 44 | 45 | namespace fxz { 46 | namespace grid { 47 | 48 | int get_plane_by_random( 49 | const std::vector& V, 50 | const std::vector& M, 51 | const size_t pn, 52 | std::vector& P) 53 | { 54 | P.reserve(4*pn); 55 | 56 | size_t vn = V.size()/3; 57 | 58 | double L[3], R[3]; 59 | for (size_t j = 0; j < 3; ++j) { 60 | L[j] = R[j] = V[j]; // initialize 61 | } 62 | 63 | for (size_t vi = 0; vi < vn; ++vi) { 64 | for (size_t j = 0; j < 3; ++j) { 65 | L[j] = std::min(L[j], V[3*vi+j]); 66 | R[j] = std::max(R[j], V[3*vi+j]); 67 | } 68 | } 69 | 70 | std::random_device rd; 71 | std::mt19937 mt(rd()); 72 | std::uniform_real_distribution uni_float(-1.0, 1.0); 73 | 74 | double eps = 1e-10; 75 | 76 | for (size_t pi = 0; pi < pn; ++pi) { 77 | double N[3]; 78 | do { 79 | for (size_t j = 0; j < 3; ++j) { 80 | N[j] = uni_float(mt); 81 | } 82 | } while (N[0]*N[0]+N[1]*N[1]+N[2]*N[2] < eps); 83 | 84 | double p[3]; 85 | double k = (uni_float(mt)+1.0)*0.5; 86 | for (size_t j = 0; j < 3; ++j) { 87 | p[j] = L[j] + (R[j]-L[j])*k; 88 | } 89 | 90 | double d = -(N[0]*p[0]+N[1]*p[1]+N[2]*p[2]); 91 | 92 | P.push_back(N[0]); 93 | P.push_back(N[1]); 94 | P.push_back(N[2]); 95 | P.push_back(d); 96 | } 97 | 98 | std::cout << "-- generate random plane number: " << pn << std::endl; 99 | 100 | return 0; 101 | } 102 | 103 | int get_plane_by_bound_box( 104 | const std::vector& V, 105 | const std::vector& M, 106 | size_t ele_n, 107 | std::vector& P) 108 | { 109 | if (ele_n == 0) { 110 | std::cerr << "# [ ERROR ] get plane by bounding box: please input right ele_n: " 111 | << ele_n << std::endl; 112 | return 1; 113 | } 114 | 115 | using namespace fxz::eigen; 116 | cmap_ematrixd mat_V(&V[0], 3, V.size()/3); 117 | FASSERT(mat_V(0,1)==V[3]); 118 | 119 | auto p_max = mat_V.rowwise().maxCoeff(); 120 | auto p_min = mat_V.rowwise().minCoeff(); 121 | 122 | auto d = p_max-p_min; 123 | 124 | double len = pow(d[0]*d[1]*d[2]/(double)ele_n, 1.0/3.0); 125 | 126 | size_t n[3]; 127 | for (size_t i = 0; i < 3; ++i) { 128 | n[i] = (size_t)(d[i]/len); 129 | if (n[i]==0) n[i] = 1; 130 | } 131 | 132 | for (size_t i = 0; i < 3; ++i) { 133 | evec3d N; 134 | N[0] = N[1] = N[2] = 0.0; 135 | N[i] = 1.0; 136 | 137 | auto dx = d/(double)(n[i]); 138 | 139 | for (size_t j = 0; j <= n[i]; ++j) { 140 | double d_val = -N.dot(p_min+dx*(double)j); 141 | if (j==n[i]) { 142 | d_val = -N.dot(p_max); 143 | } 144 | P.push_back(N[0]); 145 | P.push_back(N[1]); 146 | P.push_back(N[2]); 147 | P.push_back(d_val); 148 | } 149 | } 150 | 151 | return 0; 152 | } 153 | 154 | 155 | int get_plane_by_bound_box_xyz( 156 | const std::vector& V, 157 | const std::vector& M, 158 | size_t nx, size_t ny, size_t nz, 159 | std::vector& P) 160 | { 161 | if (nx < 1 || ny < 1 || nz < 1) { 162 | std::cerr << "# [ ERROR ] get plane by bounding box: please input right nx, ny, nz (>1): " 163 | << nx << ", " << ny << ", " << nz << std::endl; 164 | return 1; 165 | } 166 | 167 | using namespace fxz::eigen; 168 | cmap_ematrixd mat_V(&V[0], 3, V.size()/3); 169 | FASSERT(mat_V(0,1)==V[3]); 170 | 171 | auto p_max = mat_V.rowwise().maxCoeff(); 172 | auto p_min = mat_V.rowwise().minCoeff(); 173 | auto d = p_max-p_min; 174 | 175 | size_t n[3] = {nx, ny, nz}; 176 | 177 | for (size_t i = 0; i < 3; ++i) { 178 | evec3d N; 179 | N[0] = N[1] = N[2] = 0.0; 180 | N[i] = 1.0; 181 | 182 | auto dx = d/(double)(n[i]-1); 183 | 184 | for (size_t j = 0; j < n[i]; ++j) { 185 | double d_val = -N.dot(p_min+dx*(double)j); 186 | if (j==n[i]) { 187 | d_val = -N.dot(p_max); 188 | } 189 | P.push_back(N[0]); 190 | P.push_back(N[1]); 191 | P.push_back(N[2]); 192 | P.push_back(d_val); 193 | } 194 | } 195 | 196 | return 0; 197 | } 198 | 199 | 200 | int make_cut_plane(const pm_map& para) 201 | { 202 | const std::string& in_mesh = para["input"].as(); 203 | const std::string& strategy = para["strategy"].as(); 204 | 205 | const std::string& out_plane = para["output"].as(); 206 | 207 | std::vector V, P; // V: 3*vn, P: 4*pn. 208 | std::vector M; // M: 3*fn. 209 | CALL_FUNC(read_mesh(in_mesh, V, M)); 210 | 211 | if (strategy == "bound_box") { 212 | const size_t ele_n = para["num"].as(); 213 | std::cout << "-- ele num: " << ele_n << std::endl; 214 | get_plane_by_bound_box(V, M, ele_n, P); 215 | } else if (strategy == "random") { 216 | const size_t pn = para["planenum"].as(); 217 | std::cout << "-- plane num: " << pn << std::endl; 218 | get_plane_by_random(V, M, pn, P); 219 | } else if (strategy == "bound_box_xyz") { 220 | const size_t nx = para["nx"].as(); 221 | const size_t ny = para["ny"].as(); 222 | const size_t nz = para["nz"].as(); 223 | std::cout << "-- nx, ny, nz: " << nx << ", " << ny << ", " << nz << std::endl; 224 | get_plane_by_bound_box_xyz(V, M, nx, ny, nz, P); 225 | } else { 226 | std::cout << "# There is no such strategy for plane making: " 227 | << strategy << std::endl; 228 | return 0; 229 | } 230 | 231 | CALL_FUNC(write_vector(P, 4, out_plane)); 232 | 233 | return 0; 234 | } 235 | 236 | void on_strategy(const std::string& str) 237 | { 238 | std::cout << "Making planes, strategy: " << str << std::endl; 239 | } 240 | 241 | void on_element_num(size_t ele_n) 242 | { 243 | std::cout << "Making planes, element number : " << ele_n << std::endl; 244 | } 245 | 246 | int make_cut_plane(int argc, char* argv[]) 247 | { 248 | try { 249 | options_description console_desc("TopoCut Console Setting"); 250 | console_desc.add_options() 251 | ("help,h", "help screen") 252 | ("input,i", value()->notifier(on_input), "the input mesh") 253 | ("strategy,s", value()->default_value("bound_box"), "strategy for making: bound_box, bound_box_xyz, random, ...") 254 | ("num,n", value()->default_value(100), "expected element number for bounding box strtegy") 255 | ("nx", value()->default_value(10), "expected x element number for bounding box xyz strategy") 256 | ("ny", value()->default_value(10), "expected y element number for bounding box xyz strategy") 257 | ("nz", value()->default_value(10), "expected z element number for bounding box xyz strategy") 258 | ("planenum,P", value()->default_value(20), "expected plane number for random strategy") 259 | ("output,o", value()->notifier(on_output), "the output plane"); 260 | 261 | fxz::grid::pm_map vm; 262 | store(parse_command_line(argc, argv, console_desc), vm); 263 | 264 | notify(vm); 265 | 266 | if (vm.count("help")) { std::cout << console_desc << std::endl; } 267 | 268 | CALL_FUNC(fxz::grid::make_cut_plane(vm)); 269 | 270 | } catch (const error &ex) { 271 | std::cerr << ex.what() << std::endl; 272 | } 273 | 274 | return 0; 275 | } 276 | 277 | } // grid 278 | } // fxz 279 | -------------------------------------------------------------------------------- /src/tr.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of TopoCut (TopoCut: Fast and Robust Planar Cutting of Arbitrary Domains) 3 | 4 | Copyright (C) 2022, Xianzhong Fang 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | * Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | Author: Xianzhong Fang, Email: xzfangcs@163.com 33 | */ 34 | 35 | 36 | #ifndef TR_FXZ_H 37 | #define TR_FXZ_H 38 | 39 | #include 40 | #include 41 | #include "my_gmp.h" 42 | 43 | namespace fxz { 44 | namespace grid { 45 | 46 | typedef std::map, std::vector > e2f_map_type; 47 | 48 | class base_grid_mesh 49 | { 50 | public: 51 | base_grid_mesh(const std::vector& V, const std::vector& M) 52 | : V_(V), M_(M) { vn_=V_.size()/3; tn_=M_.size()/3; } 53 | 54 | const std::vector& triangles() const { return M_; } 55 | const std::vector& verts() const { return V_; } 56 | 57 | size_t tv(size_t fid, size_t id) const { assert(fid& V_; 68 | const std::vector& M_; 69 | size_t vn_; 70 | size_t tn_; 71 | }; 72 | 73 | 74 | enum cut_vert_type: char { 75 | VERT=1, EDGE=2, TRIANGLE=3, GRID=4, INNER=5 76 | }; 77 | 78 | struct base_cut_vert { 79 | public: 80 | base_cut_vert() { flag_=0; } 81 | 82 | void set_on_triangle(size_t tid) { 83 | flag_ = ((tid<<3)|(flag_&1)|2); 84 | } 85 | 86 | void set_on_edge(size_t eid) { 87 | flag_ = ((eid<<3)|(flag_&1)|4); 88 | } 89 | 90 | void set_on_vert(size_t vid) { 91 | flag_ = ((vid<<3)|(flag_&1)|6); 92 | } 93 | 94 | void set_on_grid() { flag_ |= 1; } 95 | 96 | bool is_set() const { return (flag_==0)?false:true; } 97 | 98 | bool is_grid() const { return ((flag_&1)==1)?true:false; } 99 | bool is_triangle() const { return ((flag_&6)==2)?true:false; }//01* 100 | bool is_edge() const { return ((flag_&6)==4)?true:false; } //10* 101 | bool is_vert() const { return ((flag_&6)==6)?true:false; } //11* 102 | 103 | cut_vert_type cv_type() const { 104 | if (is_vert()) return cut_vert_type::VERT; 105 | else if (is_edge()) return cut_vert_type::EDGE; 106 | else if (is_triangle()) return cut_vert_type::TRIANGLE; 107 | return cut_vert_type::GRID; 108 | } 109 | 110 | size_t ele_id() const { return (flag_>>3); } 111 | 112 | private: 113 | size_t flag_; // ele_id + bound_flag (2bit, such as vert,edge,triangle) + grid_flag (1bit) 114 | }; 115 | 116 | class cut_vert : public base_cut_vert { 117 | public: 118 | cut_vert(size_t fa, size_t fb, size_t fc) // T=>(fa(fa>=tn). 119 | { f_[0]=fa; f_[1]=fb; f_[2]=fc; id_ = INVALID_NUM; } 120 | 121 | size_t f0() const { return f_[0]; } 122 | size_t f1() const { return f_[1]; } 123 | size_t f2() const { return f_[2]; } 124 | size_t f(size_t i) const {return f_[i]; } 125 | size_t& id() { return id_; } 126 | size_t id() const { return id_; } 127 | 128 | private: 129 | size_t f_[3]; // faces id 130 | size_t id_; // cut vert id, there are repeated ones. 131 | }; 132 | 133 | struct cut_face { 134 | std::vector v; 135 | }; 136 | 137 | 138 | class table_relation { 139 | public: 140 | table_relation(const base_grid_mesh& bm, const std::vector& P) 141 | : bm_(bm), P_(P) 142 | { 143 | pn_ = P.size()/4; 144 | vn_ = bm.verts_num(); 145 | tn_ = bm.faces_num(); 146 | 147 | 148 | T_pp_.resize(pn_*(pn_-1)/2, 0); 149 | T_pv_.resize(pn_*vn_, 0); 150 | 151 | 152 | #pragma omp parallel for 153 | for (size_t i = 0; i < pn_; ++i) { 154 | for (size_t j = i+1; j < pn_; ++j) { 155 | set_pp(i, j); 156 | } 157 | } 158 | 159 | #pragma omp parallel for 160 | for (size_t i = 0; i < pn_; ++i) { 161 | for (size_t j = 0; j < vn_; ++j) { 162 | set_pv(i, j); 163 | } 164 | } 165 | 166 | tuple_pt_.resize(pn_); 167 | 168 | #pragma omp parallel for 169 | for (size_t i = 0; i < pn_; ++i) { 170 | std::list ts; 171 | for (size_t j = 0; j < tn_; ++j) { 172 | auto s = pt(i, j); 173 | if (s > 0) ts.push_back(j); 174 | } 175 | tuple_pt_[i].resize(ts.size()); 176 | std::copy(ts.begin(), ts.end(), tuple_pt_[i].begin()); 177 | } 178 | 179 | } 180 | 181 | size_t tn() const { return tn_; } 182 | size_t vn() const { return vn_; } 183 | size_t pn() const { return pn_; } 184 | const base_grid_mesh& mesh() const { return bm_; } 185 | const std::vector& plane() const { return P_; } 186 | 187 | // triangle 188 | uint8_t pt(size_t p, size_t tid) const { 189 | if (tid > bm_.triangles().size()/3) { return 5; } //invalid 190 | size_t va = bm_.triangles()[3*tid]; 191 | size_t vb = bm_.triangles()[3*tid+1]; 192 | size_t vc = bm_.triangles()[3*tid+2]; 193 | return pt(p, va, vb, vc); 194 | } 195 | 196 | uint8_t pt(size_t p, size_t va, size_t vb, size_t vc) const { 197 | short sa = pv(p, va); 198 | short sb = pv(p, vb); 199 | short sc = pv(p, vc); 200 | if (abs(sa+sb+sc)==2) return 1; 201 | else if (sa==sb && sb==sc && sc!=0) return 0; 202 | else if (sa==sb && sb==sc && sc==0) return 3; 203 | return 2; 204 | } 205 | 206 | 207 | 208 | uint8_t pe(size_t p, size_t va, size_t vb) const { 209 | short a = pv(p, va); 210 | short b = pv(p, vb); 211 | if (a==b && b!=0) { return 0; } 212 | else if (a==b && b==0) { return 2; } 213 | return 1; 214 | } 215 | 216 | void set_value(uint8_t val, size_t id, std::vector& T) { 217 | auto& s = T[id>>3]; 218 | uint16_t mask = 65535^(3<<(2*(id&7))); 219 | s = (s&mask)|(val<<(2*(id&7))); 220 | } 221 | 222 | uint8_t get_value(size_t id, const std::vector& T) const { 223 | return (((T[id>>3]>>((id&7)*2)))&3); 224 | } 225 | 226 | size_t pv_id(size_t p, size_t v) const 227 | { return p*vn_+v; } 228 | 229 | 230 | void set_pv(size_t p, size_t v) { 231 | T_pv_[pv_id(p,v)] = cal_pv(&P_[4*p], &(bm_.verts()[3*v])); 232 | } 233 | 234 | 235 | size_t pp_id(size_t pa, size_t pb) const 236 | { 237 | assert(pa != pb); 238 | if (pa > pb) { std::swap(pa, pb); } 239 | return (pn_*pa-(1+pa)*pa/2+(pb-pa)-1); 240 | } 241 | 242 | void set_pp(size_t pa, size_t pb) { 243 | if (pa != pb) { 244 | T_pp_[pp_id(pa,pb)] = cal_pp(&P_[4*pa], &P_[4*pb]); 245 | } else { 246 | std::cerr << "# [ ERROR ] pa == pb." << std::endl; 247 | } 248 | } 249 | 250 | 251 | short pv(size_t p, size_t v) const { 252 | return T_pv_[pv_id(p,v)]; 253 | } 254 | 255 | 256 | uint8_t pp(size_t pa, size_t pb) const { 257 | return T_pp_[pp_id(pa, pb)]; 258 | } 259 | 260 | const auto& tuple_pt() const { return tuple_pt_; } 261 | 262 | private: 263 | const base_grid_mesh& bm_; 264 | const std::vector& P_; 265 | size_t pn_, vn_, tn_; 266 | 267 | std::vector T_pv_; 268 | std::vector T_pp_; 269 | 270 | std::vector > tuple_pt_; 271 | }; 272 | 273 | } // grid 274 | } // fxz 275 | 276 | #endif 277 | -------------------------------------------------------------------------------- /src/my_gmp.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of TopoCut (TopoCut: Fast and Robust Planar Cutting of Arbitrary Domains) 3 | 4 | Copyright (C) 2022, Xianzhong Fang 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | * Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | Author: Xianzhong Fang, Email: xzfangcs@163.com 33 | */ 34 | 35 | 36 | #ifndef GMP_FXZ_H 37 | #define GMP_FXZ_H 38 | 39 | #include 40 | #include 41 | #include 42 | 43 | #include "common.h" 44 | 45 | namespace fxz { 46 | namespace grid { 47 | 48 | short cal_pv(const double* p, const double* v); 49 | uint8_t cal_pp(const double* pa, const double* pb); 50 | 51 | int vol_sign_with_norms(const double* na, const double* nb, const double* nc); 52 | 53 | bool cal_ppt_intersection( 54 | const double* pa, const double* pb, 55 | const double* va, const double* vb, const double* vc); 56 | 57 | void cal_ttp_point( // ttp 58 | const double* va, const double* vb, const double* p, 59 | std::pair& k); 60 | 61 | void cal_pt_point( // ptp 62 | const double* va, const double* vb, const double* vc, 63 | const double* p, const double* px, std::pair& k); 64 | 65 | // r>0, p1>p2; r<0, p1 81 | void N_star(const T& N, T& NS) 82 | { 83 | NS(0,0) = N(1,1)*N(2,2)-N(1,2)*N(2,1); 84 | 85 | NS(0,1) = -(N(0,1)*N(2,2)-N(0,2)*N(2,1)); 86 | 87 | NS(0,2) = (N(0,1)*N(1,2)-N(0,2)*N(1,1)); 88 | 89 | NS(1,0) = -(N(1,0)*N(2,2)-N(1,2)*N(2,0)); 90 | 91 | NS(1,1) = (N(0,0)*N(2,2)-N(0,2)*N(2,0)); 92 | 93 | NS(1,2) = -(N(0,0)*N(1,2)-N(0,2)*N(1,0)); 94 | 95 | NS(2,0) = (N(1,0)*N(2,1)-N(1,1)*N(2,0)); 96 | 97 | NS(2,1) = -(N(0,0)*N(2,1)-N(0,1)*N(2,0)); 98 | 99 | NS(2,2) = (N(0,0)*N(1,1)-N(0,1)*N(1,0)); 100 | } 101 | 102 | template 103 | void pp_precompute( 104 | const double* pa, const double* pb, const double* pc, 105 | Eigen::Matrix& NSd, Eigen::Matrix& dir, T& Nd) 106 | { 107 | Eigen::Matrix N, NS; 108 | N << pa[0], pa[1], pa[2], 109 | pb[0], pb[1], pb[2], 110 | pc[0], pc[1], pc[2]; 111 | 112 | N_star(N, NS); 113 | 114 | Eigen::Matrix D; 115 | D << pa[3], pb[3], pc[3]; 116 | 117 | NSd = NS*D; 118 | dir = N.row(0).cross(N.row(1)); 119 | Nd = dir.dot(N.row(2)); 120 | } 121 | 122 | template 123 | void cal_ppp_point( 124 | const Eigen::Matrix& NSd, 125 | const Eigen::Matrix& dir, 126 | const T& Nd, 127 | const double* px, std::pair& k) 128 | { 129 | Eigen::Matrix nx; 130 | nx << px[0],px[1],px[2]; 131 | k.first = nx.dot(NSd)-Nd*px[3]; 132 | k.second = Nd*(dir.dot(nx)); 133 | FASSERT(Nd != 0); 134 | } 135 | 136 | template 137 | void cal_ppp_point_coord( 138 | const Eigen::Matrix& NSd, 139 | const Eigen::Matrix& dir, 140 | const T& Nd, const double* px, 141 | Eigen::Matrix& nm, T& dm) 142 | { 143 | Eigen::Matrix nx; 144 | nx << px[0],px[1],px[2]; 145 | T ka = nx.dot(NSd)-Nd*px[3]; 146 | T kb = Nd*(dir.dot(nx)); 147 | 148 | nm = -kb*NSd+Nd*ka*dir; 149 | dm = Nd*kb; 150 | 151 | FASSERT(Nd != 0); 152 | } 153 | 154 | 155 | template 156 | void cal_ppt_point( 157 | const Eigen::Matrix& NSd, 158 | const Eigen::Matrix& dir, 159 | const T& Nd, 160 | const double* vi, const double* vj, const double* vk, 161 | std::pair& k) 162 | { 163 | using namespace fxz::eigen; 164 | Eigen::Matrix VI,VJ,VK; 165 | VI << vi[0],vi[1],vi[2]; 166 | VJ << vj[0],vj[1],vj[2]; 167 | VK << vk[0],vk[1],vk[2]; 168 | 169 | auto nt = (VJ-VI).cross(VK-VI); 170 | T dt = -VI.dot(nt); 171 | 172 | k.first = nt.dot(NSd)-Nd*dt; 173 | k.second = Nd*dir.dot(nt); 174 | } 175 | 176 | template 177 | void cal_ppt_point_coord( 178 | const Eigen::Matrix& NSd, 179 | const Eigen::Matrix& dir, 180 | const T& Nd, 181 | const double* vi, const double* vj, const double* vk, 182 | Eigen::Matrix& nm, T& dm) 183 | { 184 | using namespace fxz::eigen; 185 | Eigen::Matrix VI,VJ,VK; 186 | VI << vi[0],vi[1],vi[2]; 187 | VJ << vj[0],vj[1],vj[2]; 188 | VK << vk[0],vk[1],vk[2]; 189 | 190 | auto nt = (VJ-VI).cross(VK-VI); 191 | T dt = -VI.dot(nt); 192 | 193 | T ka = nt.dot(NSd)-Nd*dt; 194 | T kb = Nd*dir.dot(nt); 195 | 196 | nm = -kb*NSd+Nd*ka*dir; 197 | dm = Nd*kb; 198 | } 199 | 200 | 201 | template 202 | void cal_ppv_point( 203 | const Eigen::Matrix& NSd, 204 | const Eigen::Matrix& dir, 205 | const T& Nd, 206 | const double* vi, std::pair& k) 207 | { 208 | using namespace fxz::eigen; 209 | 210 | Eigen::Matrix VI; 211 | VI << vi[0], vi[1], vi[2]; 212 | 213 | k.first = (Nd*VI+NSd).dot(dir); 214 | k.second = Nd*dir.dot(dir); 215 | } 216 | 217 | size_t judge_edge_pass( 218 | const double* pa, const double* pb, 219 | const double* va, const double* vb, 220 | const double* vc, const double* vd); 221 | 222 | double cal_vol(const double* na, const double* nb, const double* nc); 223 | 224 | int vol_sgn( 225 | const double* va, const double* vb, const double* vc, const double* vd); 226 | 227 | int cal_ppp_point(const double* p0, const double* p1, const double* p2, double* rv); 228 | int cal_ppt_point( 229 | const double* p0, const double* p1, 230 | const double* vi, const double* vj, const double* vk, 231 | double* rv); 232 | int cal_ttp_point( 233 | const double* va, const double* vb, const double* p, double* rv); 234 | 235 | double dsgn(const double x); 236 | 237 | uint8_t judge_triangle_pass( 238 | const double* pa, const double* pb, 239 | const double* va, const double* vb, const double* vc); 240 | 241 | int two_edges_order_on_plane(const double* v, const double* va, const double* vb, const double* p); 242 | 243 | bool is_colinear_line(const double* va, const double* vb, const double* pa, const double* pb); 244 | 245 | bool is_triangle_and_plane_has_same_norm( 246 | const double* va, const double* vb, const double* vc, const double* p); 247 | 248 | 249 | template 250 | int cal_ttp_point_coord( 251 | const double* va, const double* vb, const double* p, 252 | Eigen::Matrix& nm, T& dm) 253 | { 254 | Eigen::Matrix N, A, B; 255 | A << va[0], va[1], va[2]; 256 | B << vb[0], vb[1], vb[2]; 257 | N << p[0], p[1], p[2]; 258 | dm = N.dot(B-A); 259 | //FASSERT(dm != 0); 260 | nm = dm*A-(N.dot(A)+p[3])*(B-A); 261 | return 0; 262 | } 263 | 264 | template 265 | int cal_ppp_point_coord( 266 | const double* pa, const double* pb, const double* pc, 267 | Eigen::Matrix& nm, T& dm) 268 | { 269 | Eigen::Matrix D; 270 | Eigen::Matrix N, NS; 271 | N << pa[0], pa[1], pa[2], 272 | pb[0], pb[1], pb[2], 273 | pc[0], pc[1], pc[2]; 274 | D << pa[3], pb[3], pc[3]; 275 | dm = N.determinant(); 276 | N_star(N, NS); 277 | nm = -NS*D; 278 | return 1; 279 | } 280 | 281 | template 282 | int cal_ppt_point_coord( 283 | const double* pa, const double* pb, 284 | const double* va, const double* vb, const double* vc, 285 | Eigen::Matrix& nm, T& dm) 286 | { 287 | Eigen::Matrix A, B, C, Na, Nb, D, Nt; 288 | Eigen::Matrix N, NS; 289 | A << va[0], va[1], va[2]; 290 | B << vb[0], vb[1], vb[2]; 291 | C << vc[0], vc[1], vc[2]; 292 | Nt = (B-A).cross(C-A); 293 | D << pa[3], pb[3], -Nt.dot(A); 294 | N << pa[0], pa[1], pa[2], 295 | pb[0], pb[1], pb[2], 296 | Nt[0], Nt[1], Nt[2]; 297 | N_star(N, NS); 298 | dm = N.determinant(); 299 | nm = -NS*D; 300 | return 1; 301 | } 302 | 303 | short choose_axis(const Eigen::Matrix& D); 304 | short choose_small_axis(const Eigen::Matrix& D); 305 | short choose_axis(const Eigen::Matrix& D); 306 | 307 | 308 | } // grid 309 | } // fxz 310 | 311 | 312 | #endif 313 | -------------------------------------------------------------------------------- /src/io.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of TopoCut (TopoCut: Fast and Robust Planar Cutting of Arbitrary Domains) 3 | 4 | Copyright (C) 2022, Xianzhong Fang 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | * Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | Author: Xianzhong Fang, Email: xzfangcs@163.com 33 | */ 34 | 35 | 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include "common.h" 42 | #include "grid.h" 43 | 44 | namespace fxz { 45 | namespace grid { 46 | 47 | 48 | /// a simple obj parser. only read vertices coordinates and faces 49 | int read_obj( 50 | const std::string& file_name, 51 | std::vector& verts, 52 | std::vector& mesh, 53 | std::vector& mesh_ptr) 54 | { 55 | std::cout << "# [ Start to read OBJ file ]" << std::endl; 56 | std::ifstream inf(file_name.c_str()); 57 | 58 | if (inf.fail()) { 59 | std::cerr << "# [ Error: read obj ] Can't open file: " 60 | << file_name << std::endl; 61 | return __LINE__; 62 | } 63 | 64 | std::vector& V = verts; 65 | std::vector& M = mesh; 66 | std::vector& MP = mesh_ptr; 67 | 68 | std::string str_line; 69 | size_t cnt = 0; 70 | while (std::getline(inf, str_line)) { 71 | std::string ty; 72 | std::istringstream ss(str_line); 73 | ss >> ty; 74 | if (ty[0] == '#') { continue; } 75 | else if (ty == "v") { 76 | double x, y, z; 77 | ss >> x >> y >> z; 78 | V.push_back(x); V.push_back(y); V.push_back(z); 79 | } else if ( ty == "f") { 80 | std::string fid_str; 81 | //mesh_ptr.push_back(mesh.size()); 82 | MP.push_back(cnt); 83 | while (ss >> fid_str) { 84 | std::istringstream fid_ss(fid_str); 85 | size_t fid; 86 | fid_ss >> fid; 87 | ++cnt; 88 | M.push_back(fid-1); 89 | } 90 | } else if ( ty == "l") { 91 | std::string fid_str; 92 | //mesh_ptr.push_back(mesh.size()); 93 | MP.push_back(cnt); 94 | while (ss >> fid_str) { 95 | std::istringstream fid_ss(fid_str); 96 | size_t fid; 97 | fid_ss >> fid; 98 | ++cnt; 99 | M.push_back(fid-1); 100 | } 101 | } 102 | } 103 | 104 | MP.push_back(cnt); 105 | 106 | if (cnt != M.size()) { 107 | std::cerr << "-- [ ERROR: read obj ] mesh size is not compatible with faces type sum." 108 | << std::endl; 109 | } 110 | 111 | std::cout << "-- Verts Num: " << V.size()/3 << std::endl; 112 | std::cout << "-- Faces Num: " << MP.size()-1 << std::endl; 113 | if (MP.size() > 1) 114 | std::cout << "-- First face type: "<< MP[1]-MP[0] << std::endl; 115 | std::cout << "# [ End: read obj.]" << std::endl; 116 | 117 | return 0; 118 | } 119 | 120 | 121 | int read_mesh( 122 | const std::string& in_mesh, 123 | std::vector& V, 124 | std::vector& M) 125 | { 126 | std::vector MP; 127 | return read_obj(in_mesh, V, M, MP); 128 | } 129 | 130 | int read_vector( 131 | const std::string& file, 132 | std::vector& P) 133 | { 134 | std::ifstream inf(file); 135 | 136 | if (inf) { 137 | size_t nr(0), nc(0); 138 | inf >> nr >> nc; 139 | if (nr*nc == 0) { 140 | std::cerr << "# [ ERROR ] the first line is not right." << std::endl; 141 | return 1; 142 | } 143 | P.reserve(nc*nr); 144 | for (size_t i = 0; i < nr; ++i) { 145 | for (size_t j = 0; j < nc; ++j) { 146 | double v; 147 | inf >> v; 148 | P.push_back(v); 149 | } 150 | } 151 | } else { 152 | std::cerr << "# [ ERROR ] can not open file: " << file << std::endl; 153 | return 1; 154 | } 155 | 156 | return 0; 157 | } 158 | 159 | int write_vector( 160 | const std::vector& P, size_t nc, 161 | const std::string& file) 162 | { 163 | if (nc == 0) { 164 | std::cout << "# [ write vector ] nc = 0." << std::endl; 165 | return 0; 166 | } 167 | size_t nr = P.size()/nc; 168 | 169 | if (nr*nc != P.size()) { 170 | std::cerr << "# [ write vetor ] nc is not compatible with vector." << std::endl; 171 | return 1; 172 | } 173 | 174 | std::ofstream outf(file); 175 | 176 | outf << nr << " " << nc << std::endl; 177 | 178 | for (size_t i = 0; i < nr; ++i) { 179 | outf << P[nc*i]; 180 | for (size_t j = 1; j < nc; ++j) { 181 | outf << " " << P[nc*i+j]; 182 | } 183 | outf << std::endl; 184 | } 185 | 186 | return 0; 187 | } 188 | 189 | 190 | int write_cutcell_to_vtk( 191 | const std::string& file, 192 | const std::vector& CV, 193 | const std::vector& CC, size_t cell_num) 194 | { 195 | std::ofstream outf(file); 196 | if (outf) { 197 | outf << "# vtk DataFile Version 4.1" << std::endl; 198 | outf << "General exact cutted cells" << std::endl; 199 | outf << "ASCII\nDATASET UNSTRUCTURED_GRID" << std::endl; 200 | size_t vn = CV.size()/3; 201 | outf << "POINTS " << vn << " float" << std::endl; 202 | 203 | for (size_t i = 0; i < CV.size(); i+=3) { 204 | outf << std::setprecision(17) << CV[i] << " " << CV[i+1] << " " << CV[i+2] << std::endl; 205 | } 206 | 207 | outf << "CELLS " << cell_num << " " << CC.size() << std::endl; 208 | size_t cnt = 0; 209 | size_t id = 0; 210 | do { 211 | size_t n = CC[id]; 212 | outf << n; //all size and fn 213 | for (size_t i = 0; i < n; ++i) { 214 | outf << " " << CC[id+1+i]; 215 | } 216 | outf << std::endl; 217 | id += n+1; 218 | ++cnt; 219 | } while (id < CC.size()); 220 | 221 | FASSERT(cnt == cell_num); 222 | 223 | outf << "CELL_TYPES " << cell_num << std::endl; 224 | for (size_t ci = 0; ci < cell_num; ++ci) { 225 | outf << 42 << std::endl; 226 | } 227 | 228 | } else { 229 | std::cerr << "# [ ERROR ] can not open file: " << file << std::endl; 230 | return 1; 231 | } 232 | 233 | 234 | return 0; 235 | } 236 | 237 | int write_obj( 238 | const std::vector& V, 239 | const std::vector >& M, 240 | const std::string& out_file) 241 | { 242 | std::ofstream outf(out_file); 243 | 244 | if (outf.fail()) { 245 | std::cerr << "-- [ ERROR ] can not open file " << out_file << std::endl; 246 | return 1; 247 | } 248 | 249 | for (size_t i = 0; i < V.size(); i+=3) { 250 | outf << std::setprecision(17) << "v " << V[i] << " " << V[i+1] << " " << V[i+2] << std::endl; 251 | } 252 | 253 | for (auto& f : M) { 254 | for (size_t i=0; i < f.size(); i+=3) { 255 | outf << "f " << f[i]+1 << " " << f[i+1]+1 << " " << f[i+2]+1 << std::endl; 256 | } 257 | } 258 | 259 | outf.close(); 260 | 261 | return 0; 262 | } 263 | 264 | 265 | int write_ply( 266 | const std::vector& V, 267 | const std::vector >& M, 268 | const std::string& out_file) 269 | { 270 | std::ofstream outf(out_file); 271 | 272 | if (outf.fail()) { 273 | std::cerr << "-- [ ERROR ] can not open file " << out_file << std::endl; 274 | return 1; 275 | } 276 | 277 | size_t fn(0); 278 | for (auto& f : M) { 279 | fn += f.size()/3; 280 | } 281 | 282 | outf << "ply\n" 283 | << "format ascii 1.0\n" 284 | << "comment write ply\n" 285 | << "element vertex " << V.size()/3 << "\n" 286 | << "property double x\n" 287 | << "property double y\n" 288 | << "property double z\n" 289 | << "element face " << fn << "\n" 290 | << "property list uchar int vertex_indices\n" 291 | << "end_header" << std::endl; 292 | 293 | 294 | for (size_t i = 0; i < V.size(); i+=3) { 295 | outf << std::setprecision(17) << V[i] << " " << V[i+1] << " " << V[i+2] << std::endl; 296 | } 297 | 298 | for (auto& f : M) { 299 | for (size_t i=0; i < f.size(); i+=3) { 300 | outf << "3 " << f[i] << " " << f[i+1] << " " << f[i+2] << std::endl; 301 | } 302 | } 303 | 304 | outf.close(); 305 | 306 | return 0; 307 | } 308 | 309 | int write_ply( 310 | const std::string& out_file, 311 | const std::vector& V, 312 | const std::vector& M) 313 | { 314 | std::ofstream outf(out_file); 315 | 316 | if (outf.fail()) { 317 | std::cerr << "-- [ ERROR ] can not open file " << out_file << std::endl; 318 | return 1; 319 | } 320 | 321 | size_t fn = M.size()/3; 322 | 323 | outf << "ply\n" 324 | << "format ascii 1.0\n" 325 | << "comment write ply\n" 326 | << "element vertex " << V.size()/3 << "\n" 327 | << "property double x\n" 328 | << "property double y\n" 329 | << "property double z\n" 330 | << "element face " << fn << "\n" 331 | << "property list uchar int vertex_indices\n" 332 | << "end_header" << std::endl; 333 | 334 | 335 | for (size_t i = 0; i < V.size(); i+=3) { 336 | outf << std::setprecision(17) << V[i] 337 | << " " << V[i+1] << " " << V[i+2] << std::endl; 338 | } 339 | 340 | for (size_t i=0; i < M.size(); i+=3) { 341 | outf << "3 " << M[i] << " " << M[i+1] 342 | << " " << M[i+2] << std::endl; 343 | } 344 | 345 | outf.close(); 346 | 347 | return 0; 348 | } 349 | 350 | int read_poly_vtk( 351 | const std::string& in_poly, 352 | std::vector& V, 353 | std::vector& C, size_t& cell_num) 354 | { 355 | std::ifstream inf(in_poly); 356 | 357 | if (inf.fail()) { 358 | std::cerr << "# [ ERROR ] cannot open file : " 359 | << in_poly << std::endl; 360 | return 1; 361 | } 362 | 363 | std::string str_line; 364 | 365 | size_t vn(0); 366 | size_t& cn = cell_num; 367 | 368 | while (std::getline(inf, str_line)) { 369 | std::string ty; 370 | std::istringstream ss(str_line); 371 | ss >> ty; 372 | if (ty == "POINTS") { 373 | ss >> vn; 374 | V.resize(3*vn); 375 | for (size_t vi = 0; vi < vn; ++vi) { 376 | std::string v_str; 377 | std::getline(inf, v_str); 378 | std::istringstream v_ss(v_str); 379 | v_ss >> V[3*vi] >> V[3*vi+1] >> V[3*vi+2]; 380 | } 381 | } else if (ty == "CELLS") { 382 | size_t nn; 383 | ss >> cn >> nn; 384 | C.reserve(nn); 385 | for (size_t ci = 0; ci < cn; ++ci) { 386 | std::string c_str; 387 | std::getline(inf, c_str); 388 | std::istringstream c_ss(c_str); 389 | size_t cell_s; 390 | c_ss >> cell_s; 391 | C.push_back(cell_s); 392 | for (size_t i = 0; i < cell_s; ++i) { 393 | size_t id; 394 | c_ss >> id; 395 | C.push_back(id); 396 | } 397 | } 398 | } else if (ty == "CELL_TYPES") { 399 | size_t n; 400 | ss >> n; 401 | if (n != cn) { 402 | std::cerr << "# [ ERROR ] cell-type size is not equal to cell size." << std::endl; 403 | return 1; 404 | } 405 | for (size_t i = 0; i < cn; ++i) { 406 | size_t id; 407 | inf >> id; 408 | if (id != 42) { 409 | std::cerr << "# [ ERROR ] cell-type is not 42, i.e., for polhedral mesh." << std::endl; 410 | return 1; 411 | } 412 | } 413 | } 414 | } 415 | 416 | inf.close(); 417 | 418 | return 0; 419 | } 420 | 421 | 422 | } // grid 423 | } // fxz 424 | -------------------------------------------------------------------------------- /src/check.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of TopoCut (TopoCut: Fast and Robust Planar Cutting of Arbitrary Domains) 3 | 4 | Copyright (C) 2022, Xianzhong Fang 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | * Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | Author: Xianzhong Fang, Email: xzfangcs@163.com 33 | */ 34 | 35 | 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | #include "common.h" 44 | #include "grid.h" 45 | #include "my_gmp.h" 46 | 47 | using namespace boost::program_options; 48 | 49 | namespace fxz { 50 | namespace grid { 51 | 52 | 53 | int check_topology( 54 | const std::vector& M, 55 | const std::map, std::vector >& e2f) 56 | { 57 | 58 | for (auto& e : e2f) { 59 | if ((e.second.size()&1) == 1) { 60 | std::cerr << "-- [ ERROR ] The mesh is not watertight." << std::endl; 61 | return 1; 62 | } else { 63 | size_t ln(0), rn(0); 64 | for (auto f : e.second) { 65 | for (size_t j = 0; j < 3; ++j) { 66 | size_t va = M[3*f+j]; 67 | size_t vb = M[3*f+(j+1)%3]; 68 | 69 | if (va == e.first.first && vb == e.first.second) { 70 | ++ln; 71 | } else if (vb == e.first.first && va == e.first.second) { 72 | ++rn; 73 | } 74 | } 75 | } // for 76 | if (ln != rn) { 77 | std::cerr << "-- [ ERROR ] The mesh is not watertight, non-manifold inner edge." << std::endl; 78 | return 1; 79 | } 80 | } // if 81 | } // for 82 | return 0; 83 | } 84 | 85 | void regularize_plane(double* P, const double norm_eps, const double len_eps) 86 | { 87 | //assert(eps > 1e-15); 88 | 89 | for (size_t i = 0; i < 4; ++i) { 90 | if ((i < 3 && fabs(P[i]) > norm_eps) || (i==3 && fabs(P[i]) > len_eps)) { 91 | if (P[i]<0) { 92 | for (size_t j = i; j < 4; ++j) { 93 | P[j] *= -1.0; 94 | } 95 | } 96 | break; 97 | } else { 98 | P[i] = 0.0; 99 | } 100 | } 101 | } 102 | 103 | struct plane_type { 104 | public: 105 | plane_type(const double* p) { 106 | for (size_t i=0; i<4; ++i) { 107 | P_[i] = p[i]; 108 | } 109 | } 110 | double operator[] (size_t id) const { return P_[id];} 111 | double P_[4]; 112 | }; 113 | 114 | double NORM_CMP_EPS; 115 | double LEN_CMP_EPS; 116 | 117 | class myc { 118 | public: 119 | bool operator()(const plane_type& A, const plane_type& B) const 120 | { 121 | if (fabs(A[0]-B[0]) > NORM_CMP_EPS) { 122 | return (A[0] < B[0]); 123 | } else if (fabs(A[1]-B[1]) > NORM_CMP_EPS) { 124 | return (A[1] < B[1]); 125 | } else if (fabs(A[2]-B[2]) > NORM_CMP_EPS) { 126 | return (A[2] < B[2]); 127 | } else if (fabs(A[3]-B[3]) > LEN_CMP_EPS) { 128 | return (A[3] < B[3]); 129 | } else { 130 | return false; // need checking 131 | } 132 | } 133 | }; 134 | 135 | int check_plane( 136 | const std::vector& P, double norm_eps, double len_eps, 137 | std::vector& invalid_p) 138 | { 139 | // regularize planes 140 | std::vector new_P(P); 141 | 142 | size_t pn = P.size()/4; 143 | 144 | { 145 | if (len_eps < 1e-15) { 146 | len_eps = 1e-15; 147 | std::cout << "-- reset len eps for plane checking: len_eps=1e-15" << std::endl; 148 | } 149 | if (norm_eps < 1e-15) { 150 | norm_eps = 1e-15; 151 | std::cout << "-- reset norm eps for plane checking: norm_eps=1e-15" << std::endl; 152 | } 153 | } 154 | 155 | std::vector flag_p(pn, 1); 156 | for (size_t i = 0; i < pn; ++i) { 157 | double len = sqrt(P[4*i]*P[4*i]+P[4*i+1]*P[4*i+1]+P[4*i+2]*P[4*i+2]); 158 | if (len < norm_eps) { 159 | std::cout << "# [ WARNING ] there exists one plane with degenerated norm: " 160 | << i << std::endl; 161 | flag_p[i] = 0; // invalid 162 | } else { 163 | for (size_t j = 0; j < 4; ++j) { 164 | new_P[4*i+j] = P[4*i+j]/len; 165 | } 166 | } 167 | } 168 | 169 | for (size_t pi = 0; pi < pn; ++pi) { 170 | regularize_plane(&new_P[4*pi], norm_eps, len_eps); 171 | } 172 | 173 | NORM_CMP_EPS=norm_eps; 174 | LEN_CMP_EPS=len_eps; 175 | 176 | std::set plane_set; 177 | 178 | size_t cnt = 0; 179 | 180 | for (size_t pi = 0; pi < pn; ++pi) { 181 | 182 | if (flag_p[pi] == 0) { 183 | invalid_p.push_back(pi); 184 | continue; 185 | } 186 | 187 | auto pt(plane_type(&new_P[4*pi])); 188 | auto it = plane_set.find(pt); 189 | 190 | if (it == plane_set.end()) { 191 | plane_set.insert(pt); 192 | } else { 193 | std::cout << "-- [ WARNING ] find repeated plane, id: " 194 | << pi << std::endl; 195 | invalid_p.push_back(pi); 196 | ++cnt; 197 | } 198 | } 199 | 200 | if (cnt > 0) { 201 | std::cout << "-- [ WARNING ] find " << cnt 202 | << " repeated planes." << std::endl; 203 | return 1; 204 | } 205 | 206 | return 0; 207 | } 208 | 209 | 210 | int check_topology(const std::vector& M) 211 | { 212 | std::map, std::vector > e2f; 213 | build_edge_to_triangle_map(M, e2f); 214 | return check_topology(M, e2f); 215 | } 216 | 217 | int check_topology(const pm_map& para) 218 | { 219 | const std::string in_mesh = para["input"].as(); 220 | 221 | std::vector V; 222 | std::vector M; 223 | CALL_FUNC(read_mesh(in_mesh, V, M)); 224 | CALL_FUNC(check_topology(M)); 225 | 226 | return 0; 227 | } 228 | 229 | 230 | double check_volume( 231 | const std::vector& V, 232 | const std::vector& M) 233 | { 234 | mpf_class sum_vol(0.0); 235 | size_t tn = M.size()/3; 236 | 237 | for (size_t ti = 0; ti < tn; ++ti) { 238 | size_t va = M[3*ti]; 239 | size_t vb = M[3*ti+1]; 240 | size_t vc = M[3*ti+2]; 241 | Eigen::Matrix A, B, C; 242 | A << V[3*va], V[3*va+1], V[3*va+2]; 243 | B << V[3*vb], V[3*vb+1], V[3*vb+2]; 244 | C << V[3*vc], V[3*vc+1], V[3*vc+2]; 245 | sum_vol += A.cross(B).dot(C); 246 | } 247 | return sum_vol.get_d(); 248 | } 249 | 250 | int check_volume( 251 | const std::vector& V, 252 | const std::vector& M, const double eps, double& sum_vol) 253 | { 254 | sum_vol = check_volume(V, M); 255 | if (sum_vol < eps) { 256 | std::cout << "-- [ ERROR ] The volume of the mesh is smaller than " << eps << std::endl; 257 | return 1; 258 | } 259 | std::cout << "-- The mesh has positive volume." << std::endl; 260 | 261 | return 0; 262 | } 263 | 264 | double ave_edge_length( 265 | const std::vector& V, 266 | const std::map, std::vector >& e2f) 267 | { 268 | typedef Eigen::Matrix evec3d; 269 | typedef Eigen::Map cmap_evec3d; 270 | 271 | double sum_len(0.0); 272 | 273 | for (auto& e2 : e2f) { 274 | size_t va = e2.first.first; 275 | size_t vb = e2.first.second; 276 | cmap_evec3d A(&V[3*va], 3, 1); 277 | cmap_evec3d B(&V[3*vb], 3, 1); 278 | double len = (A-B).norm(); 279 | sum_len += len; 280 | } 281 | 282 | return sum_len/(size_t)e2f.size(); 283 | } 284 | 285 | int check_degenerated_edge( 286 | const std::vector& V, 287 | const std::map, std::vector >& e2f, 288 | const double eps) 289 | { 290 | typedef Eigen::Matrix evec3d; 291 | typedef Eigen::Map cmap_evec3d; 292 | 293 | size_t cnt(0); 294 | 295 | for (auto& e2 : e2f) { 296 | size_t va = e2.first.first; 297 | size_t vb = e2.first.second; 298 | 299 | cmap_evec3d A(&V[3*va], 3, 1); 300 | cmap_evec3d B(&V[3*vb], 3, 1); 301 | 302 | double len = (A-B).norm(); 303 | 304 | if (len < eps) { 305 | std::cout << "-- [ ERROR ] degenerated edge: (" << va << ", " << vb 306 | << "), length is smaller than " << eps << std::endl; 307 | ++cnt; 308 | } 309 | } 310 | 311 | std::cout << "-- degenerated edge number: " << cnt << std::endl; 312 | 313 | if (cnt > 0) return 1; 314 | return 0; 315 | } 316 | 317 | int check_degenerated_triangle( 318 | const std::vector& V, 319 | const std::vector& M, const double eps) 320 | { 321 | typedef Eigen::Matrix evec3d; 322 | typedef Eigen::Map cmap_evec3d; 323 | 324 | size_t tn = M.size()/3; 325 | 326 | size_t cnt(0); 327 | 328 | for (size_t ti = 0; ti < tn; ++ti) { 329 | size_t va = M[3*ti]; 330 | size_t vb = M[3*ti+1]; 331 | size_t vc = M[3*ti+2]; 332 | 333 | cmap_evec3d A(&V[3*va], 3, 1); 334 | cmap_evec3d B(&V[3*vb], 3, 1); 335 | cmap_evec3d C(&V[3*vc], 3, 1); 336 | 337 | double vol = (B-A).cross(C-A).norm(); 338 | 339 | if (vol < eps) { 340 | std::cout << "-- [ ERROR ] degenerated triangle: " 341 | << "(" << va << ", " << vb << ", " << vc << "), volume is smaller than " 342 | << eps << std::endl; 343 | ++cnt; 344 | } 345 | } 346 | 347 | std::cout << "-- degenerated triangle number: " << cnt << std::endl; 348 | 349 | if (cnt > 0) return 1; 350 | return 0; 351 | } 352 | 353 | int check_input(const pm_map& para) 354 | { 355 | const std::string in_mesh = para["input"].as(); 356 | double eps = para["eps"].as(); 357 | 358 | std::cout << "-- mesh: " << in_mesh << std::endl; 359 | std::cout << "-- eps: " << eps << std::endl; 360 | 361 | std::vector V; 362 | std::vector M; 363 | CALL_FUNC(read_mesh(in_mesh, V, M)); 364 | 365 | if (M.size()%3 != 0) { 366 | std::cout << "-- [ ERROR ] The mesh is not triangular." << std::endl; 367 | return 1; 368 | } 369 | 370 | // check topology 371 | std::map, std::vector > e2f; 372 | CALL_FUNC(build_edge_to_triangle_map(M, e2f)); 373 | CALL_FUNC(check_topology(M, e2f)); 374 | 375 | if (e2f.size() == 0) { 376 | std::cout << "-- [ ERROR ] There is no triangle in the mesh." << std::endl; 377 | return 1; 378 | } 379 | 380 | double ave_len = ave_edge_length(V, e2f); 381 | 382 | eps *= ave_len; 383 | 384 | std::cout << "-- average length of edges: " << ave_len << std::endl; 385 | std::cout << "-- new eps considering edges: " << eps << std::endl; 386 | 387 | double all_vol(0.0); 388 | CALL_FUNC(check_volume(V, M, eps, all_vol)); 389 | 390 | CALL_FUNC(check_degenerated_triangle(V, M, eps)); 391 | 392 | return 0; 393 | } 394 | 395 | int check_input(int argc, char* argv[]) 396 | { 397 | try { 398 | options_description console_desc("TopoCcut Console Setting"); 399 | console_desc.add_options() 400 | ("help,h", "help screen") 401 | ("input,i", value()->notifier(on_input), "the input mesh") 402 | ("eps,e", value()->default_value(1e-15), "eps for degeneration checking"); 403 | 404 | fxz::grid::pm_map vm; 405 | store(parse_command_line(argc, argv, console_desc), vm); 406 | notify(vm); 407 | if (vm.count("help")) { std::cout << console_desc << std::endl; } 408 | if (fxz::grid::check_input(vm)) { 409 | std::cout << "The mesh is not valid for cutting." << std::endl; 410 | } else { 411 | std::cout << "# [ MESSAGE ] The mesh is valid." << std::endl; 412 | std::cout << "OK" << std::endl; 413 | } 414 | } catch (const error &ex) { 415 | std::cerr << ex.what() << std::endl; 416 | } 417 | 418 | return 0; 419 | } 420 | 421 | 422 | } // grid 423 | } // fxz 424 | -------------------------------------------------------------------------------- /src/my_gmp.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of TopoCut (TopoCut: Fast and Robust Planar Cutting of Arbitrary Domains) 3 | 4 | Copyright (C) 2022, Xianzhong Fang 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | * Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | Author: Xianzhong Fang, Email: xzfangcs@163.com 33 | */ 34 | 35 | 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | #include "common.h" 42 | #include "my_gmp.h" 43 | 44 | namespace fxz { 45 | namespace grid { 46 | 47 | typedef Eigen::Matrix MPF_VEC; 48 | 49 | // np^T v+dp 50 | short cal_pv(const double* p, const double* v) 51 | { 52 | mpf_class n1(p[0]),n2(p[1]),n3(p[2]),v1(v[0]),v2(v[1]),v3(v[2]),d(p[3]); 53 | mpf_class val = n1*v1+n2*v2+n3*v3+d; 54 | return sgn(val); 55 | } 56 | 57 | 58 | double cal_vol(const double* na, const double* nb, const double* nc) 59 | { 60 | using namespace fxz::eigen; 61 | cmap_evec3d N1(na, 3, 1); 62 | cmap_evec3d N2(nb, 3, 1); 63 | cmap_evec3d N3(nc, 3, 1); 64 | return N1.cross(N2).dot(N3); 65 | } 66 | 67 | int vol_sign_with_norms( 68 | const double* na, const double* nb, const double* nc) 69 | { 70 | MPF_VEC NA, NB, NC; 71 | NA << na[0], na[1], na[2]; 72 | NB << nb[0], nb[1], nb[2]; 73 | NC << nc[0], nc[1], nc[2]; 74 | 75 | return sgn(NA.cross(NB).dot(NC)); 76 | } 77 | 78 | uint8_t cal_pp(const double* pa, const double* pb) 79 | { 80 | //typedef Eigen::Matrix MPF_VEC; 81 | MPF_VEC NA, NB; 82 | NA << pa[0], pa[1], pa[2]; 83 | NB << pb[0], pb[1], pb[2]; 84 | MPF_VEC N = NA.cross(NB); 85 | int nij = abs(sgn(N[0]))+abs(sgn(N[1]))+abs(sgn(N[2])); 86 | int d = sgn((pb[3]*NA-pa[3]*NB).dot(NA)); 87 | if (nij==0 && d!=0) return 0; 88 | else if (nij!=0) return 2; 89 | else if (nij==0 && d==0) return 3; 90 | std::cerr << "# [ ERROR ] invalid relation between two planes." << std::endl; 91 | return 10; // invalid 92 | } 93 | 94 | // check whether the intersection is only one point. 95 | bool cal_ppt_intersection( 96 | const double* pa, const double* pb, 97 | const double* va, const double* vb, const double* vc) 98 | { 99 | //typedef Eigen::Matrix MPF_VEC; 100 | MPF_VEC NA, NB, VA, VB, VC; 101 | NA << pa[0], pa[1], pa[2]; 102 | NB << pb[0], pb[1], pb[2]; 103 | VA << va[0], va[1], va[2]; 104 | VB << vb[0], vb[1], vb[2]; 105 | VC << vc[0], vc[1], vc[2]; 106 | 107 | mpf_class b0 = -(pa[3]+NA.dot(VA)); 108 | mpf_class b1 = -(pb[3]+NB.dot(VA)); 109 | 110 | mpf_class M00 = NA.dot(VB-VA); 111 | mpf_class M01 = NA.dot(VC-VA); 112 | mpf_class M10 = NB.dot(VB-VA); 113 | mpf_class M11 = NB.dot(VC-VA); 114 | 115 | mpf_class det = M00*M11-M01*M10; 116 | 117 | mpf_class c0 = M11*b0-M01*b1; 118 | mpf_class c1 = -M10*b0+M00*b1; 119 | 120 | int ds = sgn(det); 121 | int s0 = sgn(c0); 122 | int s1 = sgn(c1); 123 | int s01 = sgn(det-c0-c1); 124 | 125 | if (ds == 0) {return false;} 126 | 127 | return (ds*s0>=0 && ds*s1>=0 && ds*s01>=0); 128 | } 129 | 130 | 131 | void cal_ttp_point( 132 | const double* va, const double* vb, const double* p, 133 | std::pair& k) 134 | { 135 | using namespace fxz::eigen; 136 | cmap_evecd VA(va, 3, 1); 137 | cmap_evecd VB(vb, 3, 1); 138 | cmap_evecd N(p, 3, 1); 139 | k.first = -(N.dot(VA)+p[3]); 140 | k.second = N.dot(VB-VA); 141 | } 142 | 143 | int cmp_tt_point( 144 | const double* va, const double* vb, 145 | const double* p1, const double* p2) 146 | { 147 | Eigen::Matrix VA,VB,N1,N2; 148 | VA << va[0], va[1], va[2]; 149 | VB << vb[0], vb[1], vb[2]; 150 | N1 << p1[0], p1[1], p1[2]; 151 | N2 << p2[0], p2[1], p2[2]; 152 | 153 | mpf_class ka1 = -(N1.dot(VA)+p1[3]); 154 | mpf_class ka2 = N1.dot(VB-VA); 155 | mpf_class kb1 = -(N2.dot(VA)+p2[3]); 156 | mpf_class kb2 = N2.dot(VB-VA); 157 | // ka1/ka2 : kb1/kb2 158 | return sgn(ka1*kb2-ka2*kb1)*sgn(ka2*kb2); 159 | } 160 | 161 | int cmp_tt_point_to_const( 162 | const double* va, const double* vb, const double* p, const double kc) 163 | { 164 | Eigen::Matrix VA, VB, N; 165 | VA << va[0], va[1], va[2]; 166 | VB << vb[0], vb[1], vb[2]; 167 | N << p[0], p[1], p[2]; 168 | mpf_class k1 = -(N.dot(VA)+p[3]); 169 | mpf_class k2 = N.dot(VB-VA); 170 | 171 | return sgn(k1-k2*kc)*sgn(k2); 172 | } 173 | 174 | template 175 | inline R pt_point_first(const T& VI,const T& VJ, const T& VK, const T& NP, const T& NX, const double d, const double dx) 176 | { return -(VK-VI).dot(NP)*(VJ-VI).dot((dx+VI.dot(NX))*NP-(d+VI.dot(NP))*NX); } 177 | 178 | template 179 | inline R pt_point_second(const T& VI,const T& VJ, const T& VK, const T& NP, const T& NX, const double d) 180 | { return (d+VI.dot(NP))*(NP.dot(VJ-VI)*(VI-VK).dot(NX)+NP.dot(VK-VI)*(VJ-VI).dot(NX)); } 181 | 182 | 183 | void cal_pt_point( 184 | const double* va, const double* vb, const double* vc, 185 | const double* p, const double* px, std::pair& k) 186 | { 187 | using namespace fxz::eigen; 188 | cmap_evecd VI(va, 3, 1); 189 | cmap_evecd VJ(vb, 3, 1); 190 | cmap_evecd VK(vc, 3, 1); 191 | cmap_evecd NP(p, 3, 1); 192 | cmap_evecd NX(px, 3, 1); 193 | 194 | k.first = pt_point_first(VI,VJ,VK,NP,NX,p[3],px[3]); 195 | k.second = pt_point_second(VI,VJ,VK,NP,NX,p[3]); 196 | } 197 | 198 | int cmp_pt_point( 199 | const double* va, const double* vb, const double* vc, 200 | const double* p, const double* pa, const double* pb) 201 | { 202 | MPF_VEC VI,VJ,VK,N,NA,NB; 203 | VI << va[0], va[1], va[2]; 204 | VJ << vb[0], vb[1], vb[2]; 205 | VK << vc[0], vc[1], vc[2]; 206 | N << p[0], p[1], p[2]; 207 | NA << pa[0], pa[1], pa[2]; 208 | NB << pb[0], pb[1], pb[2]; 209 | 210 | mpf_class ka1 = pt_point_first(VI,VJ,VK,N,NA,p[3],pa[3]); 211 | mpf_class ka2 = pt_point_second(VI,VJ,VK,N,NA,p[3]); 212 | mpf_class kb1 = pt_point_first(VI,VJ,VK,N,NB,p[3],pb[3]); 213 | mpf_class kb2 = pt_point_second(VI,VJ,VK,N,NB,p[3]); 214 | return sgn(ka1*kb2-ka2*kb1)*sgn(ka2*kb2); 215 | } 216 | 217 | int cmp_pt_point_to_const( 218 | const double* va, const double* vb, const double* vc, 219 | const double* p, const double* px, const double kc) 220 | { 221 | MPF_VEC VI,VJ,VK,NP,NX; 222 | VI << va[0], va[1], va[2]; 223 | VJ << vb[0], vb[1], vb[2]; 224 | VK << vc[0], vc[1], vc[2]; 225 | NP << p[0], p[1], p[2]; 226 | NX << px[0], px[1], px[2]; 227 | 228 | mpf_class k1 = pt_point_first(VI,VJ,VK,NP,NX,p[3],px[3]); 229 | mpf_class k2 = pt_point_second(VI,VJ,VK,NP,NX,p[3]); 230 | return sgn(k1-k2*kc)*sgn(k2); 231 | } 232 | 233 | size_t judge_edge_pass( 234 | const double* pa, const double* pb, 235 | const double* va, const double* vb, 236 | const double* vc, const double* vd) 237 | { 238 | MPF_VEC NA, NB, VA, VB, VC, VD; 239 | NA << pa[0], pa[1], pa[2]; 240 | NB << pb[0], pb[1], pb[2]; 241 | VA << va[0], va[1], va[2]; 242 | VB << vb[0], vb[1], vb[2]; 243 | VC << vc[0], vc[1], vc[2]; 244 | VD << vd[0], vd[1], vd[2]; 245 | 246 | MPF_VEC ni = (VB-VA).cross(VC-VA); 247 | MPF_VEC nj = (VD-VA).cross(VB-VA); 248 | MPF_VEC L = NA.cross(NB); 249 | 250 | int di = sgn(ni.dot(L)); 251 | int dj = sgn(nj.dot(L)); 252 | int r = sgn((VB-VA).dot(ni.cross(nj))); 253 | 254 | if (di*dj>0 || (di*dj==0 && r<0)) {return 1;} 255 | 256 | return 0; 257 | } 258 | 259 | int vol_sgn( 260 | const double* a, const double* b, const double* c, const double* d) 261 | { 262 | MPF_VEC A, B, C, D; 263 | A << a[0], a[1], a[2]; 264 | B << b[0], b[1], b[2]; 265 | C << c[0], c[1], c[2]; 266 | D << d[0], d[1], d[2]; 267 | 268 | return sgn((B-A).cross(C-A).dot(D-A)); 269 | } 270 | 271 | int cal_ppp_point( 272 | const double* p0, const double* p1, const double* p2, 273 | double* rv) 274 | { 275 | Eigen::Matrix NSd, dir; 276 | double Nd; 277 | pp_precompute(p0, p1, p2, NSd, dir, Nd); 278 | FASSERT2(fabs(Nd)>0, "ppp"); 279 | 280 | eigen::map_evec3d R(rv, 3, 1); 281 | R = -NSd/Nd; 282 | 283 | return 0; 284 | } 285 | 286 | int cal_ppt_point( 287 | const double* p0, const double* p1, 288 | const double* vi, const double* vj, const double* vk, 289 | double* rv) 290 | { 291 | using namespace fxz::eigen; 292 | cmap_evec3d VI(vi, 3, 1); 293 | cmap_evec3d VJ(vj, 3, 1); 294 | cmap_evec3d VK(vk, 3, 1); 295 | 296 | evec3d Nt = (VJ-VI).cross(VK-VI); 297 | double pt[4]; 298 | pt[0] = Nt[0]; 299 | pt[1] = Nt[1]; 300 | pt[2] = Nt[2]; 301 | pt[3] = -VI.dot(Nt); 302 | 303 | FASSERT(pt == &pt[0]); 304 | 305 | Eigen::Matrix NSd, dir; 306 | double Nd(0); 307 | pp_precompute(p0, p1, pt, NSd, dir, Nd); 308 | 309 | FASSERT2(fabs(Nd)>0, "ppt"); 310 | 311 | map_evec3d R(rv, 3, 1); 312 | R = -NSd/Nd; 313 | 314 | return 0; 315 | } 316 | 317 | int cal_ttp_point( 318 | const double* va, const double* vb, const double* p, 319 | double* rv) 320 | { 321 | std::pair k; 322 | cal_ttp_point(va, vb, p, k); 323 | 324 | FASSERT(fabs(k.second)>0); 325 | 326 | using namespace fxz::eigen; 327 | cmap_evec3d VA(va, 3, 1); 328 | cmap_evec3d VB(vb, 3, 1); 329 | map_evec3d R(rv, 3, 1); 330 | R = VA+(VB-VA)*k.first/k.second; 331 | 332 | return 0; 333 | } 334 | 335 | double dsgn(const double x) 336 | { 337 | if (x > 0) return 1.0; 338 | else if (x < 0) return -1.0; 339 | return 0.0; 340 | } 341 | 342 | uint8_t judge_triangle_pass( 343 | const double* pa, const double* pb, 344 | const double* va, const double* vb, const double* vc) 345 | { 346 | //typedef Eigen::Matrix MPF_VEC; 347 | MPF_VEC NA, NB, A, B, C; 348 | NA << pa[0], pa[1], pa[2]; 349 | NB << pb[0], pb[1], pb[2]; 350 | A << va[0], va[1], va[2]; 351 | B << vb[0], vb[1], vb[2]; 352 | C << vc[0], vc[1], vc[2]; 353 | 354 | int r = sgn((B-A).cross(C-A).dot(NA.cross(NB))); 355 | 356 | if (r != 0) return 1; 357 | return 0; 358 | } 359 | 360 | 361 | int two_edges_order_on_plane( 362 | const double* v, const double* va, const double* vb, const double* p) 363 | { 364 | //typedef Eigen::Matrix MPF_VEC; 365 | MPF_VEC N, V, A, B; 366 | N << p[0] , p[1], p[2]; 367 | V << v[0], v[1], v[2]; 368 | A << va[0], va[1], va[2]; 369 | B << vb[0], vb[1], vb[2]; 370 | 371 | return sgn((A-V).cross(B-V).dot(N)); 372 | } 373 | 374 | // assume the line is passing one point of the edge. 375 | bool is_colinear_line(const double* va, const double* vb, const double* pa, const double* pb) 376 | { 377 | //typedef Eigen::Matrix MPF_VEC; 378 | MPF_VEC NA, NB, A, B; 379 | A << va[0], va[1], va[2]; 380 | B << vb[0], vb[1], vb[2]; 381 | NA << pa[0], pa[1], pa[2]; 382 | NB << pb[0], pb[1], pb[2]; 383 | 384 | 385 | MPF_VEC c = (A-B).cross(NA.cross(NB)); 386 | 387 | if (sgn(c[0])==0 && sgn(c[1])==0 && sgn(c[2])==0) { 388 | return true; 389 | } 390 | return false; 391 | } 392 | 393 | bool is_triangle_and_plane_has_same_norm( 394 | const double* va, const double* vb, const double* vc, const double* p) 395 | { 396 | 397 | MPF_VEC A, B, C, N; 398 | A << va[0], va[1], va[2]; 399 | B << vb[0], vb[1], vb[2]; 400 | C << vc[0], vc[1], vc[2]; 401 | N << p[0], p[1], p[2]; 402 | 403 | int s = sgn((B-A).cross(C-A).dot(N)); 404 | 405 | return (s>0); 406 | } 407 | 408 | // |x|<=eps, 0; x > eps, 1; x < -eps, -1; 409 | int my_sgn(const mpf_class& x, const double eps) 410 | { 411 | // cmp: a>b, 1; a& D) 419 | { 420 | auto s01 = cmp(abs(D[0]),abs(D[1])); 421 | auto s02 = cmp(abs(D[0]),abs(D[2])); 422 | auto s12 = cmp(abs(D[1]),abs(D[2])); 423 | 424 | if (s01>=0 && s02>=0) { return sgn(D[0]); } 425 | if (s01<=0 && s12>=0) { return sgn(D[1])*2; } 426 | 427 | return sgn(D[2])*3; 428 | } 429 | 430 | short choose_small_axis(const Eigen::Matrix& D) 431 | { 432 | auto s01 = cmp(abs(D[0]),abs(D[1])); 433 | auto s02 = cmp(abs(D[0]),abs(D[2])); 434 | auto s12 = cmp(abs(D[1]),abs(D[2])); 435 | 436 | if (s01<=0 && s02<=0) { return sgn(D[0]); } 437 | if ((s01>=0 && s12<=0)) { return sgn(D[1])*2; } 438 | 439 | return sgn(D[2])*3; 440 | } 441 | 442 | short choose_axis(const Eigen::Matrix& D) 443 | { 444 | if (fabs(D[0])>=fabs(D[1]) && fabs(D[0])>=fabs(D[2])) { return dsgn(D[0]); } 445 | if (fabs(D[0])<=fabs(D[1]) && fabs(D[1])>=fabs(D[2])) { return dsgn(D[1])*2; } 446 | return dsgn(D[2])*3; 447 | } 448 | 449 | 450 | } //grid 451 | } //fxz 452 | -------------------------------------------------------------------------------- /src/triangulate.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of TopoCut (TopoCut: Fast and Robust Planar Cutting of Arbitrary Domains) 3 | 4 | Copyright (C) 2022, Xianzhong Fang 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | * Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | Author: Xianzhong Fang, Email: xzfangcs@163.com 33 | */ 34 | 35 | 36 | #include 37 | 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | #include "common.h" 44 | #include "grid.h" 45 | #include "my_gmp.h" 46 | 47 | #include 48 | 49 | namespace fxz { 50 | namespace grid { 51 | 52 | short choose_axis(const Eigen::Matrix& D); 53 | 54 | 55 | struct FaceInfo2 56 | { 57 | FaceInfo2(){} 58 | int nesting_level; 59 | bool in_domain(){ return nesting_level%2 == 1; } 60 | }; 61 | typedef CGAL::Exact_predicates_inexact_constructions_kernel K; 62 | typedef CGAL::Triangulation_vertex_base_2 Vb; 63 | typedef CGAL::Triangulation_face_base_with_info_2 Fbb; 64 | typedef CGAL::Constrained_triangulation_face_base_2 Fb; 65 | typedef CGAL::Triangulation_data_structure_2 TDS; 66 | typedef CGAL::Exact_predicates_tag Itag; 67 | typedef CGAL::Constrained_Delaunay_triangulation_2 CDT; 68 | typedef CDT::Point Point; 69 | typedef CGAL::Polygon_2 Polygon_2; 70 | 71 | 72 | void mark_domains( 73 | CDT& ct, CDT::Face_handle start, int index, std::list& border) 74 | { 75 | if(start->info().nesting_level != -1){ 76 | return; 77 | } 78 | std::list queue; 79 | queue.push_back(start); 80 | while(! queue.empty()){ 81 | CDT::Face_handle fh = queue.front(); 82 | queue.pop_front(); 83 | if(fh->info().nesting_level == -1){ 84 | fh->info().nesting_level = index; 85 | for(int i = 0; i < 3; i++){ 86 | CDT::Edge e(fh,i); 87 | CDT::Face_handle n = fh->neighbor(i); 88 | if(n->info().nesting_level == -1){ 89 | if(ct.is_constrained(e)) border.push_back(e); 90 | else queue.push_back(n); 91 | } 92 | } 93 | } 94 | } 95 | } 96 | void mark_domains(CDT& cdt) 97 | { 98 | for(CDT::All_faces_iterator it = cdt.all_faces_begin(); it != cdt.all_faces_end(); ++it){ 99 | it->info().nesting_level = -1; 100 | } 101 | std::list border; 102 | mark_domains(cdt, cdt.infinite_face(), 0, border); 103 | while(! border.empty()){ 104 | CDT::Edge e = border.front(); 105 | border.pop_front(); 106 | CDT::Face_handle n = e.first->neighbor(e.second); 107 | if(n->info().nesting_level == -1){ 108 | mark_domains(cdt, n, e.first->info().nesting_level+1, border); 109 | } 110 | } 111 | } 112 | 113 | 114 | int triangulate_with_CGAL( 115 | const std::vector& UV, 116 | std::vector& tris) 117 | { 118 | using namespace CGAL; 119 | 120 | CDT cdt; 121 | 122 | std::map c2id; 123 | { 124 | Polygon_2 cgal_polygon; 125 | for (size_t i = 0; i < UV.size(); i+=2) { 126 | Point P(UV[i], UV[i+1]); 127 | cgal_polygon.push_back(P); 128 | c2id.insert(std::make_pair(P, i/2)); 129 | } 130 | cdt.insert_constraint(cgal_polygon.vertices_begin(), cgal_polygon.vertices_end(), true); 131 | } 132 | 133 | mark_domains(cdt); 134 | 135 | for (CDT::Finite_faces_iterator fit=cdt.finite_faces_begin(); 136 | fit!=cdt.finite_faces_end();++fit) { 137 | if ( fit->info().in_domain() ) { 138 | for (size_t i = 0; i < 3; ++i) { 139 | tris.push_back(c2id[fit->vertex(i)->point()]); 140 | } 141 | } 142 | } 143 | 144 | 145 | return 0; 146 | } 147 | 148 | int check_triangles_area( 149 | const std::vector& UV, 150 | const std::vector& tris) 151 | { 152 | for (size_t i = 0; i < tris.size(); i+=3) { 153 | size_t va(tris[i]), vb(tris[i+1]), vc(tris[i+2]); 154 | Eigen::Matrix pa, pb, pc; 155 | pa << UV[2*va], UV[2*va+1]; 156 | pb << UV[2*vb], UV[2*vb+1]; 157 | pc << UV[2*vc], UV[2*vc+1]; 158 | auto ab = pb-pa; 159 | auto ac = pc-pa; 160 | mpf_class area = ab[0]*ac[1]-ab[1]*ac[0]; 161 | if (sgn(area)<=0) { 162 | std::cerr << "-- [ WARNING ] negative triangle." << std::endl; 163 | } 164 | } 165 | 166 | return 0; 167 | } 168 | 169 | int triangulate_face( 170 | const std::vector& V, 171 | const std::vector& f, 172 | std::vector& tris) 173 | { 174 | tris.reserve(3*(f.size()-2)); 175 | 176 | if (f.size() == 3) { 177 | tris = f; 178 | } 179 | else { 180 | Eigen::Map > O(&V[3*f[0]], 3, 1); 181 | Eigen::Matrix sum_N; 182 | sum_N.setZero(); 183 | for (size_t i = 1; i+1 < f.size(); ++i) { 184 | Eigen::Map > A(&V[3*f[i]], 3, 1); 185 | Eigen::Map > B(&V[3*f[i+1]], 3, 1); 186 | sum_N += (A-O).cross(B-O); 187 | } 188 | short direc = choose_axis(sum_N); 189 | 190 | 191 | size_t x = abs(direc)%3; // +1 192 | size_t y = (abs(direc)+1)%3;//+2 193 | if (direc < 0) std::swap(x, y); 194 | 195 | std::vector UV(2*f.size()); 196 | for (size_t i = 0; i < f.size(); ++i) { 197 | UV[2*i] = V[3*f[i]+x]; 198 | UV[2*i+1] = V[3*f[i]+y]; 199 | } 200 | 201 | triangulate_with_CGAL(UV, tris); 202 | check_triangles_area(UV, tris); //for test 203 | 204 | for (auto& v : tris) { 205 | v = f[v]; 206 | } 207 | } 208 | 209 | return 0; 210 | } 211 | 212 | 213 | int triangulate_cut_mesh( 214 | size_t ori_vn, double all_vol, 215 | const std::vector& V, 216 | const std::vector& CC, 217 | size_t cn, 218 | std::vector >& faces_tris, 219 | std::vector& tris_CC, 220 | size_t& new_cn) 221 | { 222 | std::vector > all_faces; // faces 223 | std::vector > all_cells; // cells 224 | 225 | // -> faces id list 226 | std::map, std::vector > faces_key_map; 227 | std::vector faces_pair; // faces pair flag; 228 | 229 | { 230 | size_t cnt(0); 231 | for (size_t i = 0; i < CC.size(); i+=CC[i]+1) { 232 | size_t fn = CC[i+1]; 233 | cnt += fn; 234 | } 235 | all_faces.reserve(cnt); 236 | faces_pair.resize(cnt, INVALID_NUM); 237 | } 238 | 239 | all_cells.reserve(cn); 240 | 241 | size_t face_id(0); 242 | 243 | for (size_t i = 0; i < CC.size(); i+=CC[i]+1) { 244 | size_t fn = CC[i+1]; 245 | std::vector fs; 246 | fs.reserve(fn); 247 | for (size_t j = i+2; j < i+CC[i]+1; j+=CC[j]+1) { 248 | size_t vn = CC[j]; 249 | std::vector f; 250 | f.reserve(vn); 251 | for (size_t k = 0; k < CC[j]; ++k) { 252 | f.push_back(CC[j+k+1]); 253 | } 254 | all_faces.push_back(f); 255 | 256 | { 257 | size_t vs_sum = std::accumulate(f.begin(), f.end(), 0); 258 | auto it = faces_key_map.find(std::make_pair(vn, vs_sum)); 259 | if (it == faces_key_map.end()) { 260 | std::vector list_fs; 261 | list_fs.reserve(2); 262 | list_fs.push_back(face_id); 263 | faces_key_map.insert(std::make_pair(std::make_pair(vn, vs_sum), list_fs)); 264 | } else { 265 | it->second.push_back(face_id); 266 | } 267 | } 268 | fs.push_back(face_id); 269 | ++face_id; 270 | } 271 | 272 | all_cells.push_back(fs); 273 | } // for 274 | 275 | FASSERT(face_id == all_faces.size()); 276 | FASSERT(all_cells.size() == cn); 277 | 278 | for (auto& s : faces_key_map) { 279 | const auto& fs_ids = s.second; 280 | if (fs_ids.size() == 1) {continue;} 281 | 282 | std::vector fs_str; 283 | fs_str.reserve(fs_ids.size()); 284 | for (auto& fid : fs_ids) { 285 | std::vector f = all_faces[fid]; 286 | std::sort(f.begin(), f.end()); 287 | std::stringstream ss; 288 | std::copy(f.begin(), f.end(), std::ostream_iterator(ss, ",")); 289 | fs_str.push_back(ss.str()); 290 | } 291 | for (size_t i = 0; i < fs_str.size(); ++i) { 292 | for (size_t j = i+1; j < fs_str.size(); ++j) { 293 | if (fs_str[i] == fs_str[j]) { 294 | faces_pair[fs_ids[i]] = fs_ids[j]; 295 | faces_pair[fs_ids[j]] = fs_ids[i]; 296 | break; 297 | } 298 | } 299 | } 300 | } 301 | 302 | faces_tris.resize(faces_pair.size()); 303 | // triangulate each faces 304 | #pragma omp parallel for 305 | for (size_t i = 0; i < faces_pair.size(); ++i) { 306 | std::vector& tris = faces_tris[i]; 307 | 308 | if (faces_pair[i] != INVALID_NUM) { 309 | FASSERT(faces_pair[faces_pair[i]] == i); 310 | if (faces_pair[i] > i) { // only one side is triangulated 311 | triangulate_face(V, all_faces[i], tris); 312 | } 313 | } else { // boundary faces, convex, directly triangulate it 314 | const auto& f = all_faces[i]; 315 | tris.reserve(3*(f.size()-2)); 316 | for (size_t j = 1; j+1 < f.size(); ++j) { 317 | tris.push_back(f[0]); 318 | tris.push_back(f[j]); 319 | tris.push_back(f[j+1]); 320 | } 321 | } 322 | 323 | FASSERT(tris.size()%3==0); 324 | } 325 | 326 | FASSERT(faces_tris.size() == faces_pair.size()); 327 | 328 | 329 | new_cn = cn; 330 | for (size_t ci = 0; ci < cn; ++ci) { 331 | size_t tris_fn(0); 332 | for (auto fid : all_cells[ci]) { 333 | const auto& f = faces_tris[fid].size()>0 ? faces_tris[fid] : faces_tris[faces_pair[fid]]; 334 | tris_fn += f.size()/3; 335 | FASSERT(f.size()%3 == 0); 336 | } 337 | 338 | tris_CC.push_back(1+tris_fn+3*tris_fn); 339 | tris_CC.push_back(tris_fn); 340 | 341 | std::vector tris_M; 342 | 343 | bool is_bd = false; 344 | bool is_connect_inner=false; 345 | 346 | for (auto fid : all_cells[ci]) { 347 | FASSERT(fid < faces_pair.size()); 348 | if (faces_pair[fid] == INVALID_NUM) { 349 | is_bd = true; 350 | } else { 351 | is_connect_inner = true; 352 | } 353 | 354 | const auto& f = faces_tris[fid].size()>0 ? faces_tris[fid] : faces_tris[faces_pair[fid]]; 355 | 356 | FASSERT(f.size() >= 3 && f.size()%3 == 0); 357 | short direc = faces_tris[fid].size()>0 ? 1 : -1; 358 | for (size_t i = 0; i < f.size(); i+=3) { 359 | tris_CC.push_back(3); 360 | tris_CC.push_back(f[i]); 361 | 362 | tris_M.push_back(f[i]); 363 | 364 | if (direc > 0) { 365 | tris_CC.push_back(f[i+1]); 366 | tris_CC.push_back(f[i+2]); 367 | 368 | tris_M.push_back(f[i+1]); 369 | tris_M.push_back(f[i+2]); 370 | 371 | } else { 372 | tris_CC.push_back(f[i+2]); 373 | tris_CC.push_back(f[i+1]); 374 | 375 | tris_M.push_back(f[i+2]); 376 | tris_M.push_back(f[i+1]); 377 | } 378 | } 379 | }// for all_cells 380 | 381 | auto r_topo = check_topology(tris_M); 382 | double cell_vol = check_volume(V, tris_M); 383 | if (is_bd && is_connect_inner && r_topo==0 && (cell_vol>=0 && (cell_vol) <= 1e-6*all_vol)) { 384 | size_t all_n = 2+4*tris_fn; 385 | for (size_t i = 0; i < all_n; ++i) { 386 | tris_CC.pop_back(); 387 | } 388 | --new_cn; 389 | } 390 | }//for ci 391 | 392 | return 0; 393 | } 394 | 395 | int triangulate_cut_mesh( 396 | const std::string& out_mesh, 397 | size_t ori_vn, double all_vol, 398 | const std::vector& V, 399 | const std::vector& CC, 400 | size_t cn) 401 | { 402 | std::vector > faces_tris; 403 | std::vector tris_CC; 404 | size_t new_cn; 405 | 406 | CALL_FUNC_WITH_CLOCK( 407 | triangulate_cut_mesh( 408 | ori_vn, all_vol, V, CC, cn, 409 | faces_tris, tris_CC, new_cn), 410 | "triangulate-cut-mesh"); 411 | 412 | // CALL_FUNC(write_ply(V, faces_tris, out_mesh+"-tri.ply")); 413 | // std::cout << "-- write triangles ply into file: " << out_mesh+"-tri.ply" << std::endl; 414 | 415 | CALL_FUNC(write_cutcell_to_vtk( 416 | out_mesh+"-tri.vtk", V, tris_CC, new_cn)); 417 | std::cout << "-- write triangulated cut-mesh into file: " << out_mesh+"-tri.vtk" << std::endl; 418 | 419 | 420 | return 0; 421 | } 422 | 423 | } // grid 424 | } // fxz 425 | -------------------------------------------------------------------------------- /src/seq.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of TopoCut (TopoCut: Fast and Robust Planar Cutting of Arbitrary Domains) 3 | 4 | Copyright (C) 2022, Xianzhong Fang 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | * Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | Author: Xianzhong Fang, Email: xzfangcs@163.com 33 | */ 34 | 35 | 36 | #ifndef SEQ_FXZ_H 37 | #define SEQ_FXZ_H 38 | 39 | 40 | #include 41 | #include 42 | 43 | #include "common.h" 44 | #include "tr.h" 45 | #include "union_find_set.h" 46 | 47 | namespace fxz { 48 | namespace grid{ 49 | 50 | enum class cycle_sort_type : short { 51 | SIMPLE=0, FULL=1 52 | }; 53 | 54 | enum class line_sort_type : short { 55 | NONE=0,LINE_COORD=1, POINT_COORD=2, 56 | }; 57 | 58 | class sequence_type { 59 | public: 60 | sequence_type( 61 | const table_relation& tr, 62 | const e2f_map_type& e2f, 63 | const std::vector& eid_map, 64 | const double seq_eps, 65 | std::vector& cut_verts, 66 | std::vector& CV, 67 | line_sort_type lst=line_sort_type::POINT_COORD) 68 | : tr_(tr), e2f_(e2f), eid_map_(eid_map), 69 | seq_eps_(seq_eps), cv_(cut_verts), CV_(CV), lst_(lst) 70 | { 71 | switch (lst_) { 72 | case line_sort_type::LINE_COORD: 73 | //std::cout << "-- line sort type: line coordinates." << std::endl; 74 | break; 75 | case line_sort_type::POINT_COORD: 76 | //std::cout << "-- line sort type: point coordinates." << std::endl; 77 | break; 78 | default: 79 | std::cerr << "# [ ERROR ] there is no such line sort type." << std::endl; 80 | exit(1); 81 | } 82 | build_v2f(); 83 | } 84 | 85 | int build_v2f(); 86 | 87 | int run(); 88 | int reset_cutvert_type(); 89 | 90 | const std::vector& get_cut_verts() ; 91 | const std::vector& cut_verts_coord() const { return CV_; } 92 | std::vector& cut_verts_coord() { return CV_; } 93 | 94 | const std::vector& get_cut_verts_type(); 95 | const std::vector& cut_verts_type() const { return CV_type_; } 96 | 97 | // unique id -> cut vert id. 98 | // here unique id is the vert id of input mesh M, 99 | // will return an id out of scope of cut verts. 100 | const std::vector& get_cut_verts_id(); 101 | const std::vector& cut_verts_id() const { return CV_id_; } 102 | 103 | int cal_cv_coord(const cut_vert& v, double* coord) const; 104 | int get_cut_edges( 105 | std::vector& cv_type, 106 | std::vector& edge_CE, 107 | std::vector& tri_CE, 108 | std::vector& grid_in_CE, 109 | std::vector& grid_out_CE) const; 110 | 111 | template 112 | int get_cut_vert_coord( 113 | const cut_vert& x, 114 | std::pair,T>& c) const 115 | { 116 | std::vector t_id, p_id; 117 | t_id.reserve(3); 118 | p_id.reserve(3); 119 | 120 | for (size_t i = 0; i < 3; ++i) { 121 | if (x.f(i) < tr_.tn()) { 122 | t_id.push_back(i); 123 | } else { 124 | p_id.push_back(i); 125 | } 126 | } 127 | 128 | FASSERT(t_id.size()<3); 129 | if (t_id.size()==2) { // ttp 130 | std::unordered_set fa_v; 131 | for (size_t i = 0; i < 3; ++i) { 132 | size_t vid = tr_.mesh().tv(x.f(t_id[0]), i); 133 | fa_v.insert(vid); 134 | } 135 | std::vector cm_v; 136 | cm_v.reserve(2); 137 | for (size_t i = 0; i < 3; ++i) { 138 | size_t vid = tr_.mesh().tv(x.f(t_id[1]), i); 139 | if (fa_v.count(vid) > 0) { 140 | cm_v.push_back(vid); 141 | } 142 | } 143 | size_t p = x.f(p_id[0]) - tr_.tn(); 144 | FASSERT(cm_v.size() == 2); 145 | cal_ttp_point_coord( 146 | &tr_.mesh().verts()[3*cm_v[0]], 147 | &tr_.mesh().verts()[3*cm_v[1]], 148 | &tr_.plane()[4*p], 149 | c.first, c.second); 150 | 151 | } else if (t_id.size()==1) { // ppt 152 | 153 | size_t pa = x.f(p_id[0]) - tr_.tn(); 154 | size_t pb = x.f(p_id[1]) - tr_.tn(); 155 | bool is_vert = false; 156 | std::vector v3(3); 157 | for (size_t i = 0; i < 3; ++i) { 158 | v3[i] = tr_.mesh().tv(x.f(t_id[0]), i); 159 | 160 | if (tr_.pv(pa, v3[i])==0 && tr_.pv(pb, v3[i])==0) { 161 | is_vert = true; 162 | auto vert = tr_.mesh().vert_coord(v3[i]); 163 | c.first << vert[0], vert[1], vert[2]; 164 | c.second = 1.0; 165 | break; 166 | } 167 | } 168 | 169 | if (!is_vert) { 170 | cal_ppt_point_coord( 171 | &tr_.plane()[4*pa], 172 | &tr_.plane()[4*pb], 173 | &tr_.mesh().verts()[3*v3[0]], 174 | &tr_.mesh().verts()[3*v3[1]], 175 | &tr_.mesh().verts()[3*v3[2]], 176 | c.first, c.second); 177 | } 178 | 179 | } else { // ppp 180 | 181 | size_t pa = x.f(p_id[0]) - tr_.tn(); 182 | size_t pb = x.f(p_id[1]) - tr_.tn(); 183 | size_t pc = x.f(p_id[2]) - tr_.tn(); 184 | cal_ppp_point_coord( 185 | &tr_.plane()[4*pa], 186 | &tr_.plane()[4*pb], 187 | &tr_.plane()[4*pc], 188 | c.first, c.second); 189 | } 190 | 191 | return 0; 192 | } 193 | 194 | 195 | struct tt_point { 196 | public: 197 | tt_point(size_t a, size_t b) : cvid(a), plane(b) { } 198 | size_t cvid, plane; 199 | }; 200 | 201 | struct pt_point { 202 | public: 203 | pt_point(size_t a, size_t b) : cvid(a), plane(b) { } 204 | size_t cvid, plane; 205 | }; 206 | 207 | struct pp_point { 208 | public: 209 | pp_point(size_t a, size_t b) : cvid(a), face(b) { } 210 | size_t cvid, face; // triangle or plane 211 | }; 212 | 213 | const table_relation& tr() const { return tr_; } 214 | 215 | int classify(); 216 | void add_pp(size_t cvid, size_t a, size_t b, size_t c); 217 | void add_pt(size_t cvid, size_t a, size_t b, size_t c); 218 | void add_tt(size_t cvid, size_t eid, size_t fid); 219 | 220 | int sort_tt(); 221 | 222 | 223 | int sort_pp(); 224 | 225 | int keep_pp_inner(); 226 | size_t find_third_vert(size_t va, size_t vb, const size_t* M); 227 | uint8_t passing_triangle(size_t pa, size_t pb, size_t fid); 228 | uint8_t passing_edge(size_t eid, size_t pa, size_t pb, const std::vector& fs); 229 | 230 | 231 | 232 | typedef Eigen::Matrix MPF_VEC; 233 | 234 | uint8_t passing_vert(size_t vid, size_t pa, size_t pb); 235 | void cal_pt_outer_direc( 236 | size_t vid, size_t pid, 237 | const std::vector& fs, 238 | std::vector& dt) const; 239 | 240 | // > 2 adjacent triangles 241 | int cycle_sort_triangles( 242 | size_t vid, size_t pid, 243 | const std::vector& dt, 244 | const std::unordered_map& fs2id, 245 | std::vector& fs, 246 | std::vector& cp, std::vector& dir, 247 | cycle_sort_type cst=cycle_sort_type::FULL) const; 248 | int sort_equal_triangles( 249 | size_t vid, size_t pid, 250 | std::vector& fs, 251 | std::vector& cp) const; 252 | 253 | // in the plane and vert 254 | int sort_equal_triangles( 255 | size_t vid, size_t pid, 256 | std::vector& fs) const; 257 | 258 | int plane_triangle_edge_direc( 259 | const std::unordered_map& fs2id, 260 | const std::vector& dt, 261 | const std::vector& V, 262 | const std::vector& M, 263 | const MPF_VEC& NP, size_t f) const; 264 | 265 | 266 | int cycle_sort_verts( 267 | size_t vid, size_t pid, const std::vector& bd_fs, 268 | std::vector >& bd_fans); 269 | bool is_bound_fan( 270 | size_t vid, const std::vector >& bd_fans, 271 | size_t pid, 272 | size_t fa, size_t fb); 273 | uint8_t passing_cycle_fan( 274 | size_t vid, 275 | const std::vector >& bd_fans, 276 | size_t pa, size_t pb, 277 | const std::vector& dt, 278 | std::unordered_map& fs2id, 279 | const std::vector& cut_fs, 280 | const std::vector& cp, 281 | const std::vector& dir); 282 | 283 | 284 | // 1: inner, 0: bound/outer 285 | // fan: , pass line: dk*ks 286 | int judge_fan( 287 | const MPF_VEC& N, const MPF_VEC& di, const MPF_VEC& dj, 288 | const MPF_VEC& dk, int ks) const; 289 | 290 | 291 | int judge_full_fan( 292 | const MPF_VEC& N, const MPF_VEC& di, 293 | const MPF_VEC& dk, int ks) const; 294 | 295 | int keep_pp_inner(size_t pa, size_t pb, size_t seq_id); 296 | size_t find_edge_cv(size_t va, size_t vb, size_t pid); 297 | int sort_pt(); 298 | 299 | 300 | //// interface 301 | int sort_tt_api( 302 | const std::pair& e, 303 | std::vector& seq) 304 | { 305 | switch(lst_) { 306 | case line_sort_type::LINE_COORD: 307 | return sort_tt_with_lc(e, seq); 308 | case line_sort_type::POINT_COORD: 309 | return sort_tt_with_coord(e, seq); 310 | default: 311 | std::cerr << "# [ ERROR ] the sort type is not right!" << std::endl; 312 | exit(1); 313 | } 314 | return 1; 315 | } 316 | 317 | int sort_pp_api(size_t pa, size_t pb, std::vector& seq) 318 | { 319 | switch(lst_) { 320 | case line_sort_type::LINE_COORD: 321 | return sort_pp_with_lc(pa, pb, seq); 322 | case line_sort_type::POINT_COORD: 323 | return sort_pp_with_coord(pa, pb, seq); 324 | default: 325 | std::cerr << "# [ ERROR ] the sort type is not right!" << std::endl; 326 | exit(1); 327 | } 328 | return 1; 329 | } 330 | 331 | int sort_pt_api(size_t pt_id, size_t pid, size_t tid, std::vector& seq) 332 | { 333 | switch(lst_) { 334 | case line_sort_type::LINE_COORD: 335 | return sort_pt_with_lc(pt_id, pid, tid, seq); 336 | case line_sort_type::POINT_COORD: 337 | return sort_pt_with_coord(pt_id, pid, tid, seq); 338 | default: 339 | std::cerr << "# [ ERROR ] the sort type is not right!" << std::endl; 340 | exit(1); 341 | } 342 | return 1; 343 | } 344 | 345 | 346 | ////////// 347 | // sort with parametric coordinates 348 | int sort_tt_with_lc( 349 | const std::pair& e, 350 | std::vector& seq); 351 | int sort_pp_with_lc(size_t pa, size_t pb, std::vector& seq); 352 | int sort_pt_with_lc(size_t pt_id, size_t pid, size_t tid, std::vector& seq); 353 | ////////// 354 | 355 | ////////// 356 | // sort with one component of coordinates 357 | int sort_tt_with_coord(const std::pair& e, std::vector& seq); 358 | int sort_pp_with_coord(size_t pa, size_t pb, std::vector& seq); 359 | int sort_pt_with_coord(size_t pt_id, size_t pid, size_t tid, std::vector& seq); 360 | ////////// 361 | 362 | int move_cv_on_line(std::vector& new_CV, char& is_move) const; 363 | int move_cut_verts(std::vector& new_CV) const; 364 | 365 | int move_cv( 366 | std::vector& V, 367 | const std::vector& vs, 368 | short d, bool is_fix_bd, const Eigen::Matrix& D, 369 | char& is_move) const; 370 | 371 | const std::map, size_t>& edge_map_to_id() const { return e2id_; } 372 | size_t edge_id(const std::pair& ev) const 373 | { 374 | auto it = e2id_.find(ev); 375 | if (it != e2id_.end()) { 376 | return it->second; 377 | } 378 | return INVALID_NUM; 379 | } 380 | 381 | const std::pair& edge_v(size_t eid) const { return eid_map_[eid]->first; } 382 | 383 | const std::vector& seq_tt(size_t eid) const { return seq_tt_[eid]; } 384 | const std::vector& seq_pt(size_t id) const { return seq_pt_[id]; } 385 | const std::vector& seq_pp(size_t id) const { return seq_pp_[id]; } 386 | const std::vector& seq_pp_s(size_t id) const { return pp_s_[id]; } 387 | 388 | const std::map,size_t>& pt_map() const { return pt_map_; } 389 | const std::pair& pt_bd(size_t id) const { return seq_pt_bound_[id]; } 390 | 391 | const std::map,size_t>& pp_map() const { return pp_map_; } 392 | 393 | const cut_vert& cv(size_t cvid) const { FASSERT(cvid& ev(size_t eid) const { return eid_map_[eid]->first; } 396 | const std::vector& edge_fs(size_t eid) const { return eid_map_[eid]->second; } 397 | const std::vector& CV() const { return CV_; } 398 | const char pt_dir(size_t id) const { return seq_pt_dir_[id]; } 399 | 400 | const size_t ori_cv_num() const { return cv_.size(); } 401 | const size_t pure_cv_num() const { return pure_cv_num_; } 402 | 403 | const std::vector& v2f(size_t vid) const { FASSERT(vid& eid_map_; 409 | 410 | std::vector > v2f_; 411 | 412 | double seq_eps_; 413 | 414 | // will be modified after sorting 415 | std::vector& cv_; 416 | 417 | size_t tn_; 418 | std::map, size_t> e2id_; 419 | std::vector > seq_tt_; 420 | 421 | // pp lines 422 | std::map,size_t> pp_map_; 423 | std::vector > seq_pp_; 424 | std::vector > pp_s_; 425 | 426 | // pt lines, 427 | std::map,size_t> pt_map_; 428 | std::vector > seq_pt_; 429 | std::vector > seq_pt_bound_; 430 | std::vector seq_pt_dir_;//'+':the same;'-':opposite of the standard dir (np x nt) 431 | 432 | union_find_set ufs_; 433 | size_t pure_cv_num_; 434 | 435 | 436 | std::vector& CV_; 437 | std::vector CV_type_; 438 | std::vector CV_id_; 439 | 440 | line_sort_type lst_; 441 | 442 | }; 443 | 444 | } // grid 445 | } // fxz 446 | 447 | #endif 448 | -------------------------------------------------------------------------------- /src/grid.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of TopoCut (TopoCut: Fast and Robust Planar Cutting of Arbitrary Domains) 3 | 4 | Copyright (C) 2022, Xianzhong Fang 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | * Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | Author: Xianzhong Fang, Email: xzfangcs@163.com 33 | */ 34 | 35 | 36 | 37 | #include 38 | #include 39 | #include 40 | 41 | 42 | #include "grid.h" 43 | #include "my_gmp.h" 44 | 45 | 46 | using namespace boost::program_options; 47 | 48 | namespace fxz { 49 | namespace grid { 50 | 51 | 52 | int general_exact_cut(int argc, char* argv[]) 53 | { 54 | try { 55 | options_description console_desc("TopoCut Console Setting"); 56 | console_desc.add_options() 57 | ("help,h", "help screen") 58 | ("input,i", value()->notifier(on_input), "the input mesh") 59 | ("plane,p", value()->notifier(on_plane), "the input planes") 60 | ("is-triangulate", value()->default_value(0), "whether to triangulate cut-faces (0 or 1)") 61 | ("is-round-and-embed", value()->default_value(1), "whether to do rounding and embedding (0 or 1)") 62 | ("is-connect-hole", value()->default_value(1), "whether to connect holes in cut-planes (0 or 1)") 63 | ("eps,e", value()->default_value(1e-20), "used for detecting degeneration") 64 | ("line_sort_eps_ratio", value()->default_value(1e-3), "used for coarse line-sorting") 65 | ("planeeps,E", value()->default_value(1e-2), "used for detecting repeated plane") 66 | ("detecplane", value()->default_value(1), "detec input planes (0 or 1)") 67 | ("output,o", value()->notifier(on_output), "the output mesh"); 68 | 69 | fxz::grid::pm_map vm; 70 | store(parse_command_line(argc, argv, console_desc), vm); 71 | 72 | notify(vm); 73 | 74 | if (vm.count("help")) { std::cout << console_desc << std::endl; } 75 | else { 76 | CALL_FUNC(fxz::grid::general_exact_cut(vm)); 77 | } 78 | 79 | } catch (const error &ex) { 80 | std::cerr << ex.what() << std::endl; 81 | } 82 | 83 | return 0; 84 | } 85 | 86 | 87 | void reduce_precision(double& x, size_t p) 88 | { 89 | std::stringstream ss; 90 | ss << std::setprecision(p) << x; 91 | ss >> x; 92 | } 93 | 94 | int reduce_precision(std::vector& V, size_t p) 95 | { 96 | for (auto& x : V) { 97 | reduce_precision(x, p); 98 | } 99 | 100 | return 0; 101 | } 102 | 103 | int general_exact_cut(const pm_map& para) 104 | { 105 | // read input triangular mesh 106 | const std::string& in_mesh = para["input"].as(); 107 | const std::string& in_plane = para["plane"].as(); 108 | const std::string& out_mesh = para["output"].as(); 109 | 110 | std::vector V, P; // V: 3*vn, P: 4*pn. 111 | std::vector M; // M: 3*fn. 112 | CALL_FUNC(read_mesh(in_mesh, V, M)); 113 | CALL_FUNC(read_vector(in_plane, P)); 114 | 115 | std::cout << "-- plane number: " << P.size()/4 << std::endl; 116 | 117 | if (P.size() == 0) { 118 | std::cout << "-- [ WARNING ] there is no input plane." << std::endl; 119 | return 2; 120 | } 121 | 122 | if (M.size() == 0) { 123 | std::cout << "-- [ WARNING ] there is no input triangle." 124 | << std::endl; 125 | return 3; 126 | } 127 | 128 | 129 | std::vector CV, new_CV; 130 | std::vector CC; 131 | size_t cn(0); 132 | double all_vol(0.0); 133 | CALL_FUNC_WITH_CLOCK( 134 | general_exact_cut(para, out_mesh, V, M, P, CV, CC, cn, new_CV, all_vol), 135 | "generate-cut-mesh"); 136 | 137 | if (cn > 0) { 138 | CALL_FUNC(write_cutcell_to_vtk(out_mesh, new_CV, CC, cn)); 139 | std::cout << "-- write out mesh into file: " << out_mesh << std::endl; 140 | 141 | const size_t is_triangulate = para["is-triangulate"].as(); 142 | if (is_triangulate == 1) { 143 | CALL_FUNC(triangulate_cut_mesh( 144 | out_mesh, V.size()/3, all_vol, new_CV, CC, cn)); 145 | } 146 | 147 | } else { 148 | std::cout << "-- [ WARNING ] there is no output cut-cell." << std::endl; 149 | return 1; 150 | } 151 | 152 | return 0; 153 | } 154 | 155 | /////////////////////////////////////////////////////////////////// 156 | //// general exact cut 157 | /////////////////////////////////////////////////////////////////// 158 | 159 | int generate_PPP( 160 | const table_relation& tr, 161 | std::list& cut_verts) 162 | { 163 | size_t tn = tr.tn(); 164 | size_t pn = tr.pn(); 165 | auto& P = tr.plane(); 166 | 167 | std::vector > plane_cv(pn); 168 | 169 | /// PPP 170 | #pragma omp parallel for 171 | for (size_t pi = 0; pi < pn; ++pi) {// 172 | auto& pcv = plane_cv[pi]; 173 | 174 | for (size_t pj = pi+1; pj < pn; ++pj) {// 175 | for (size_t pk = pj+1; pk < pn; ++pk) {// 176 | if (tr.pp(pi,pj)==2 && tr.pp(pi,pk)==2 177 | && tr.pp(pj,pk)==2) { 178 | int r = vol_sign_with_norms( 179 | &P[4*pi], &P[4*pj], &P[4*pk]); 180 | 181 | if (r != 0) { 182 | pcv.push_back(cut_vert(tn+pi,tn+pj,tn+pk)); 183 | pcv.back().set_on_grid(); 184 | } // if 185 | } // if 186 | } // for pk 187 | } // for pj 188 | } // for pi 189 | 190 | 191 | for (auto& cv : plane_cv) { 192 | cut_verts.insert(cut_verts.end(), cv.begin(), cv.end()); 193 | } 194 | 195 | return 0; 196 | } 197 | 198 | int generate_TTP( 199 | const table_relation& tr, 200 | const std::map, std::vector >& e2f, 201 | std::list& cut_verts) 202 | { 203 | size_t pn = tr.pn(); 204 | size_t tn = tr.tn(); 205 | 206 | { // simple method 207 | size_t eid = 0; 208 | for (const auto& e : e2f) { 209 | size_t va = e.first.first; 210 | size_t vb = e.first.second; 211 | for (size_t pi = 0; pi < pn; ++pi) { 212 | if (tr.pe(pi, va, vb) == 1) { 213 | for (size_t k = 0; k+1 < e.second.size(); k+=2) { 214 | size_t fa = e.second[k]; 215 | size_t fb = e.second[k+1]; 216 | if (fa > fb) std::swap(fa, fb); 217 | cut_verts.push_back(cut_vert(fa,fb,pi+tn));//TTP 218 | cut_verts.back().set_on_edge(eid); 219 | } 220 | } 221 | } 222 | ++eid; 223 | } 224 | } 225 | return 0; 226 | } 227 | 228 | int generate_PPT( 229 | const table_relation& tr, 230 | std::list& cut_verts) 231 | { 232 | size_t pn = tr.pn(); 233 | size_t tn = tr.tn(); 234 | auto& P = tr.plane(); 235 | auto& V = tr.mesh().verts(); 236 | auto& M = tr.mesh().triangles(); 237 | 238 | std::vector > plane_cv(pn); 239 | 240 | /// PPT 241 | #pragma omp parallel for 242 | for (size_t pi = 0; pi < pn; ++pi) { 243 | auto& pcv = plane_cv[pi]; 244 | 245 | for (size_t pj = pi+1; pj < pn; ++pj) { 246 | if (tr.pp(pi, pj)==2) { 247 | std::list com_ts; 248 | { 249 | // precondition, LA and LB is ordered from small to large. 250 | const auto& LA = tr.tuple_pt()[pi]; 251 | const auto& LB = tr.tuple_pt()[pj]; 252 | for (size_t id_pi=0,id_pj=0; id_pi LB[id_pj]) { 256 | ++id_pj; 257 | } else { 258 | com_ts.push_back(LA[id_pi]); 259 | ++id_pi; ++id_pj; 260 | } 261 | } 262 | 263 | } 264 | //for (size_t ti = 0; ti < tn; ++ti) { // simple method 265 | for (auto ti : com_ts) { 266 | auto si = tr.pt(pi, ti); 267 | auto sj = tr.pt(pj, ti); 268 | const size_t* const vp = &M[3*ti]; 269 | 270 | bool is_add = false; 271 | if (si==2 && sj==2) { 272 | is_add = cal_ppt_intersection( 273 | &P[4*pi], &P[4*pj], 274 | &V[3*vp[0]], &V[3*vp[1]], &V[3*vp[2]]); 275 | } else if (si==1 && 276 | ( (tr.pv(pj, vp[0])==0&&tr.pv(pi,vp[0])==0) 277 | || (tr.pv(pj, vp[1])==0&&tr.pv(pi,vp[1])==0) 278 | || (tr.pv(pj, vp[2])==0&&tr.pv(pi,vp[2])==0) ) ) 279 | { is_add = true; } 280 | else if (sj==1 && 281 | ( (tr.pv(pi, vp[0])==0&&tr.pv(pj,vp[0])==0) 282 | || (tr.pv(pi, vp[1])==0&&tr.pv(pj,vp[1])==0) 283 | || (tr.pv(pi, vp[2])==0&&tr.pv(pj,vp[2])==0) ) ) 284 | { is_add = true; } 285 | 286 | if (is_add) { 287 | pcv.push_back(cut_vert(pi+tn, pj+tn, ti)); 288 | pcv.back().set_on_triangle(ti); 289 | } 290 | }// for ti 291 | }// if 292 | }// for pj 293 | }// for pi 294 | 295 | for (auto& cv : plane_cv) { 296 | cut_verts.insert(cut_verts.end(), cv.begin(), cv.end()); 297 | } 298 | 299 | return 0; 300 | } 301 | 302 | int generate_cut_verts( 303 | const table_relation& tr, 304 | const std::map, std::vector >& e2f, 305 | std::vector& cut_verts) 306 | { 307 | std::vector > triples(3); 308 | std::vector triple_name={"PPP","TTP","PPT"}; 309 | 310 | CALL_FUNC(generate_PPP(tr, triples[0])); 311 | CALL_FUNC(generate_TTP(tr, e2f, triples[1])); 312 | CALL_FUNC(generate_PPT(tr, triples[2])); 313 | 314 | cut_verts.reserve(triples[0].size()+triples[1].size()+triples[2].size()); 315 | for (size_t i = 0; i < 3; ++i) { 316 | cut_verts.insert(cut_verts.end(), triples[i].begin(), triples[i].end()); 317 | std::cout << "-- " << triple_name[i] << " num : " << triples[i].size() << std::endl; 318 | } 319 | std::cout << "-- all triples of (PPP,TTP,PPT) : " << cut_verts.size() << std::endl; 320 | 321 | return 0; 322 | } 323 | 324 | typedef std::pair vert_pair; 325 | 326 | int sort_adjacent_triangles( 327 | const std::vector& V, 328 | const std::vector& M, 329 | std::map >& e2f) 330 | { 331 | for (auto& ts : e2f) { 332 | if (ts.second.size() == 0) { return 1; } 333 | 334 | auto& faces = ts.second; 335 | size_t va = ts.first.first; 336 | size_t vb = ts.first.second; 337 | 338 | FASSERT(va < vb); 339 | 340 | { 341 | size_t k = INVALID_NUM; 342 | for (size_t i = 0; i < faces.size(); ++i) { 343 | size_t fid = faces[i]; 344 | for (size_t j = 0; j < 3; ++j) { 345 | if (M[3*fid+j]==va && M[3*fid+(j+1)%3]==vb) {//norm outer forward 346 | k = i; 347 | break; 348 | } 349 | } 350 | if (k != INVALID_NUM) { 351 | break; 352 | } 353 | } 354 | FASSERT(k != INVALID_NUM); 355 | if (k != 0) { 356 | std::swap(faces[0], faces[k]); 357 | } 358 | } 359 | 360 | if (ts.second.size() == 2) { continue; } 361 | 362 | std::vector third_vs; 363 | third_vs.reserve(faces.size()); 364 | 365 | for (auto& t : faces) { 366 | for (size_t k = 0; k < 3; ++k) { 367 | if (M[3*t+k]!=va && M[3*t+k]!=vb) { 368 | third_vs.push_back(M[3*t+k]); 369 | break; 370 | } 371 | } 372 | } 373 | 374 | FASSERT(third_vs.size() == faces.size()); 375 | 376 | std::vector si(faces.size(), 0); 377 | for (size_t i = 1; i < si.size(); ++i) { 378 | si[i] = vol_sgn(&V[3*va], &V[3*third_vs[0]], &V[3*third_vs[i]], &V[3*vb]); 379 | } 380 | 381 | // Here, there is an assumption that there is no self-intersection. 382 | std::vector new_third_vs, new_fs; 383 | new_third_vs.reserve(faces.size()); 384 | new_fs.reserve(faces.size()); 385 | 386 | // push the first 387 | new_fs.push_back(faces[0]); 388 | new_third_vs.push_back(third_vs[0]); 389 | 390 | for (size_t i = 1; i < si.size(); ++i) { 391 | if (si[i] < 0) { 392 | new_fs.push_back(faces[i]); 393 | new_third_vs.push_back(third_vs[i]); 394 | } 395 | } 396 | 397 | for (size_t i = 1; i < new_third_vs.size(); ++i) { 398 | for (size_t j = i+1; j < new_third_vs.size(); ++j) { 399 | int r = vol_sgn(&V[3*va], &V[3*new_third_vs[i]], &V[3*new_third_vs[j]], &V[3*vb]); 400 | if (r > 0) { 401 | std::swap(new_third_vs[i], new_third_vs[j]); 402 | std::swap(new_fs[i], new_fs[j]); 403 | } 404 | FASSERT(r != 0); 405 | 406 | } 407 | } 408 | 409 | for (size_t i = 1; i < si.size(); ++i) { 410 | if (si[i] == 0) { 411 | new_fs.push_back(faces[i]); 412 | new_third_vs.push_back(third_vs[i]); 413 | } 414 | } 415 | 416 | size_t last_s = new_third_vs.size(); 417 | for (size_t i = 1; i < si.size(); ++i) { 418 | if (si[i] > 0) { 419 | new_fs.push_back(faces[i]); 420 | new_third_vs.push_back(third_vs[i]); 421 | } 422 | } 423 | 424 | FASSERT(third_vs.size() == new_third_vs.size()); 425 | 426 | for (size_t i = last_s; i < new_third_vs.size(); ++i) { 427 | for (size_t j = i+1; j < new_third_vs.size(); ++j) { 428 | int r = vol_sgn(&V[3*va], &V[3*new_third_vs[i]], &V[3*new_third_vs[j]], &V[3*vb]); 429 | if (r > 0) { 430 | std::swap(new_third_vs[i], new_third_vs[j]); 431 | std::swap(new_fs[i], new_fs[j]); 432 | } 433 | FASSERT(r != 0); 434 | } 435 | } 436 | 437 | std::swap(ts.second, new_fs); 438 | 439 | } // for e2f 440 | 441 | return 0; 442 | } 443 | 444 | int build_edge_to_triangle_map( 445 | const std::vector& M, 446 | std::map >& e2f) 447 | { 448 | for (size_t i = 0; i+2 < M.size(); i+=3) { 449 | for (size_t j = 0; j < 3; ++j) { 450 | vert_pair e(M[i+j], M[i+(j+1)%3]); 451 | 452 | if (e.first > e.second) { 453 | std::swap(e.first, e.second); 454 | } 455 | 456 | auto it = e2f.find(e); 457 | if (it != e2f.end()) { 458 | it->second.push_back(i/3); 459 | } else { 460 | std::vector fs; 461 | fs.reserve(2); 462 | fs.push_back(i/3); 463 | e2f.insert(std::make_pair(e, fs)); 464 | } 465 | } 466 | } 467 | 468 | return 0; 469 | } 470 | 471 | int build_edge_to_triangle_map( 472 | const std::vector& V, 473 | const std::vector& M, 474 | std::map >& e2f) 475 | { 476 | CALL_FUNC(build_edge_to_triangle_map(M, e2f)); 477 | 478 | // sort triangles adjacent to each edge with more than 2 adjacent faces. 479 | CALL_FUNC(sort_adjacent_triangles(V, M, e2f)); 480 | 481 | return 0; 482 | } 483 | 484 | int check_delete_repeated_plane( 485 | std::vector& P, const double norm_eps, const double len_eps) 486 | { 487 | std::vector invalid_P; 488 | 489 | if (check_plane(P, norm_eps, len_eps, invalid_P)) { 490 | std::vector new_P; 491 | new_P.reserve(P.size()); 492 | 493 | size_t pn = P.size()/4; 494 | size_t cnt = 0; 495 | for (size_t pi=0; pi& V, 516 | const std::vector& M, 517 | std::vector& P, 518 | std::vector& CV, 519 | std::vector& CC, size_t& cn, std::vector& new_CV, double& all_vol) 520 | { 521 | 522 | std::cout << "-- default prec: " << mpf_get_default_prec() << std::endl; 523 | size_t mpf_prec = 4096; // enough for 32 float-point input 524 | mpf_set_default_prec(mpf_prec); 525 | std::cout << "-- set prec: " << mpf_prec << std::endl; 526 | 527 | auto tmp_bm_start = std::chrono::high_resolution_clock::now(); 528 | 529 | base_grid_mesh bound_mesh(V, M); 530 | 531 | std::map > e2f; 532 | CALL_FUNC(build_edge_to_triangle_map(V, M, e2f)); 533 | 534 | const double ave_len = ave_edge_length(V, e2f); 535 | 536 | std::cout << "-- edges num : " << e2f.size() << std::endl; 537 | std::cout << "-- average length: " << ave_len << std::endl; 538 | 539 | double eps = para["eps"].as(); 540 | std::cout << "-- eps for detecting degeneration: " << eps 541 | << std::endl; 542 | eps *= ave_len; 543 | std::cout << "-- eps (considering average length): " << eps 544 | << std::endl; 545 | { 546 | CALL_FUNC(check_topology(M, e2f)); 547 | CALL_FUNC(check_volume(V, M, eps, all_vol)); 548 | CALL_FUNC(check_degenerated_triangle(V, M, eps)); 549 | } 550 | 551 | { 552 | double plane_eps = para["planeeps"].as(); 553 | std::cout << "-- eps for detecting plane degeneration (for norm): " << plane_eps 554 | << std::endl; 555 | double len_eps = plane_eps*ave_len; 556 | std::cout << "-- eps (considering average length): " 557 | << len_eps << std::endl; 558 | 559 | const size_t is_detec_plane = para["detecplane"].as(); 560 | if (is_detec_plane == 1) { 561 | CALL_FUNC(check_delete_repeated_plane(P, plane_eps, len_eps)); 562 | } 563 | 564 | if (P.size() == 0) { 565 | std::cout << "-- [ ERROR ] there is no input plane after plane checking." << std::endl; 566 | return 1; 567 | } 568 | } 569 | 570 | 571 | auto tmp_bm_end = std::chrono::high_resolution_clock::now(); 572 | 573 | { 574 | double time_taken=std::chrono::duration_cast(tmp_bm_end - tmp_bm_start).count(); 575 | time_taken *= 1e-9; 576 | std::cout << "--- Time taken by program build-and-check-mesh is " 577 | << std::fixed << time_taken << std::setprecision(9) 578 | << " sec" << std::endl; 579 | } 580 | 581 | table_relation tr(bound_mesh, P); 582 | 583 | std::vector cut_verts; 584 | 585 | CALL_FUNC(generate_cut_verts(tr, e2f, cut_verts)); 586 | 587 | std::vector eid_map; 588 | eid_map.reserve(e2f.size()); 589 | for (e2f_map_type::iterator it = e2f.begin(); it != e2f.end(); ++it) { 590 | eid_map.push_back(it); 591 | } 592 | 593 | // set seq eps 594 | const double seq_eps_ratio = para["line_sort_eps_ratio"].as(); 595 | std::cout << "-- seq eps ratio: " << seq_eps_ratio << std::endl; 596 | const double seq_eps = ave_len*seq_eps_ratio; 597 | std::cout << "-- seq eps: " << seq_eps << std::endl; 598 | 599 | line_sort_type lst(line_sort_type::LINE_COORD); 600 | sequence_type seq(tr, e2f, eid_map, seq_eps, cut_verts, CV, lst); 601 | 602 | CALL_FUNC(seq.run()); 603 | 604 | seq.get_cut_verts_type(); 605 | seq.get_cut_verts_id(); // calculate CV id, will be used in cell building 606 | 607 | std::vector > face_triangles; 608 | CALL_FUNC(generate_cut_cells(para, seq, output_file+"-cf", CC, cn, 609 | new_CV, face_triangles)); 610 | 611 | return 0; 612 | } 613 | 614 | } // namespace grid 615 | } // fxz 616 | -------------------------------------------------------------------------------- /example/eight.obj: -------------------------------------------------------------------------------- 1 | #### 2 | # 3 | # OBJ File Generated by Meshlab 4 | # 5 | #### 6 | # Object eight.obj 7 | # 8 | # Vertices: 315 9 | # Faces: 634 10 | # 11 | #### 12 | v -0.142420 0.065177 0.260608 13 | v -0.181989 0.076540 0.271445 14 | v -0.123893 0.066093 0.329939 15 | v -0.122979 0.064590 0.188283 16 | v 0.142420 0.065177 -0.260608 17 | v 0.181989 0.076540 -0.271445 18 | v 0.123893 0.066093 -0.329939 19 | v 0.122979 0.064590 -0.188283 20 | v -0.072239 -0.014726 -0.341881 21 | v -0.017838 -0.014627 -0.366416 22 | v -0.039749 0.043670 -0.372418 23 | v -0.099600 -0.066092 -0.359901 24 | v -0.032912 -0.066020 -0.395573 25 | v -0.138410 -0.065466 -0.296287 26 | v -0.135170 -0.077707 -0.393831 27 | v -0.049677 -0.077763 -0.440679 28 | v 0.068739 -0.068686 -0.390190 29 | v 0.072239 -0.014726 0.341881 30 | v 0.017838 -0.014627 0.366416 31 | v 0.039749 0.043670 0.372418 32 | v 0.099600 -0.066092 0.359901 33 | v 0.032912 -0.066020 0.395573 34 | v 0.138410 -0.065466 0.296287 35 | v 0.135170 -0.077707 0.393831 36 | v 0.049677 -0.077763 0.440679 37 | v -0.068739 -0.068686 0.390190 38 | v -0.045055 -0.055361 -0.476864 39 | v -0.037186 -0.014824 -0.499314 40 | v 0.051296 -0.044322 -0.483565 41 | v -0.126475 -0.014757 -0.465447 42 | v 0.150198 0.055570 -0.424934 43 | v 0.060284 0.068494 -0.459204 44 | v 0.135079 0.077725 -0.392823 45 | v 0.045055 -0.055361 0.476864 46 | v 0.037186 -0.014824 0.499314 47 | v -0.051296 -0.044322 0.483565 48 | v 0.126475 -0.014757 0.465447 49 | v -0.150198 0.055570 0.424934 50 | v -0.060284 0.068494 0.459204 51 | v -0.135079 0.077725 0.392823 52 | v 0.188724 0.013117 0.082286 53 | v 0.233576 0.010949 0.199004 54 | v 0.215392 -0.043248 0.185690 55 | v 0.156431 0.043450 0.020495 56 | v 0.171897 0.000092 0.002021 57 | v 0.162866 0.035579 -0.035095 58 | v -0.188724 0.013117 -0.082286 59 | v -0.233576 0.010949 -0.199004 60 | v -0.215392 -0.043248 -0.185690 61 | v -0.156431 0.043450 -0.020495 62 | v -0.171897 0.000092 -0.002021 63 | v -0.162866 0.035579 0.035095 64 | v -0.067313 0.014873 0.490898 65 | v 0.021715 0.044742 0.489868 66 | v -0.126516 0.014972 0.465443 67 | v -0.214720 0.015203 0.374161 68 | v -0.176897 0.015193 0.425242 69 | v -0.236797 0.015313 0.316273 70 | v -0.193127 0.066315 0.349240 71 | v -0.208420 0.067939 0.286047 72 | v -0.229263 0.043816 0.250443 73 | v -0.214658 0.043635 0.184550 74 | v -0.130377 0.078643 0.137373 75 | v 0.067313 0.014873 -0.490898 76 | v -0.021715 0.044742 -0.489868 77 | v 0.126516 0.014972 -0.465443 78 | v 0.214720 0.015203 -0.374161 79 | v 0.176897 0.015193 -0.425242 80 | v 0.236797 0.015313 -0.316273 81 | v 0.193127 0.066315 -0.349240 82 | v 0.208420 0.067939 -0.286047 83 | v 0.229263 0.043816 -0.250443 84 | v 0.214658 0.043635 -0.184550 85 | v 0.181744 -0.076895 -0.225204 86 | v 0.141494 -0.076729 -0.390420 87 | v 0.212561 -0.067863 -0.284234 88 | v 0.199134 -0.043974 -0.379903 89 | v 0.224567 -0.043744 -0.324583 90 | v 0.233145 -0.014538 -0.201222 91 | v 0.242955 -0.014647 -0.261574 92 | v 0.156545 -0.043448 -0.017204 93 | v 0.163391 -0.035324 0.038619 94 | v 0.188528 0.001833 -0.078150 95 | v 0.194436 -0.025458 -0.109043 96 | v -0.181744 -0.076895 0.225204 97 | v -0.141494 -0.076729 0.390420 98 | v -0.212561 -0.067863 0.284234 99 | v -0.199134 -0.043974 0.379903 100 | v -0.224567 -0.043744 0.324583 101 | v -0.233145 -0.014538 0.201222 102 | v -0.242955 -0.014647 0.261574 103 | v -0.156545 -0.043448 0.017204 104 | v -0.163391 -0.035324 -0.038619 105 | v -0.188528 0.001833 0.078150 106 | v -0.194436 -0.025458 0.109043 107 | v -0.006718 -0.041711 -0.133416 108 | v 0.069747 -0.071193 -0.115051 109 | v -0.039011 -0.076564 -0.103399 110 | v 0.192968 -0.066144 0.349289 111 | v 0.149444 -0.055219 0.425539 112 | v 0.068472 0.068833 0.390202 113 | v 0.091510 0.028661 0.330536 114 | v 0.106919 -0.017598 0.296052 115 | v 0.122356 -0.042525 0.244251 116 | v 0.109380 -0.041514 0.199886 117 | v 0.148483 -0.069250 0.225265 118 | v 0.111048 -0.071410 0.151511 119 | v 0.198237 0.068094 0.337988 120 | v 0.182439 0.044243 0.406197 121 | v 0.236321 0.014962 0.322550 122 | v 0.214756 -0.014995 0.374311 123 | v 0.176985 -0.015124 0.425130 124 | v 0.243695 0.014726 0.262496 125 | v 0.227091 -0.043871 0.308431 126 | v 0.229584 -0.043650 0.250875 127 | v 0.177985 -0.075834 0.246262 128 | v 0.201340 -0.070830 0.270330 129 | v -0.198237 0.068094 -0.337988 130 | v -0.182439 0.044243 -0.406197 131 | v -0.236321 0.014962 -0.322550 132 | v -0.243695 0.014726 -0.262496 133 | v -0.215975 0.054756 -0.201749 134 | v -0.216058 0.065555 -0.270604 135 | v -0.130747 0.073971 -0.079098 136 | v -0.154051 0.054750 -0.064135 137 | v -0.068472 0.068833 -0.390202 138 | v -0.091510 0.028661 -0.330536 139 | v -0.106919 -0.017598 -0.296052 140 | v -0.122356 -0.042525 -0.244251 141 | v -0.109380 -0.041514 -0.199886 142 | v -0.148483 -0.069250 -0.225265 143 | v -0.117365 0.029066 -0.274731 144 | v -0.112650 0.000764 -0.268704 145 | v -0.112501 0.029427 -0.214335 146 | v -0.104553 0.001720 -0.211251 147 | v -0.119854 0.054039 -0.314476 148 | v -0.139580 0.071459 -0.324689 149 | v -0.137664 0.077821 -0.381521 150 | v -0.134682 0.054062 -0.246484 151 | v -0.157216 0.071046 -0.245232 152 | v -0.072145 -0.052976 -0.145240 153 | v -0.067260 -0.026653 -0.159535 154 | v -0.016679 0.000263 -0.144728 155 | v -0.069480 0.001467 -0.166527 156 | v -0.078129 0.028679 -0.165774 157 | v -0.055533 0.043972 -0.142594 158 | v -0.114030 0.053191 -0.183583 159 | v -0.132300 0.070511 -0.172194 160 | v -0.066408 0.072769 -0.112665 161 | v -0.182880 0.077035 -0.246568 162 | v -0.198380 0.070615 -0.206609 163 | v -0.109991 0.043758 -0.462619 164 | v -0.086940 0.072150 -0.443723 165 | v -0.192968 -0.066144 -0.349289 166 | v -0.149444 -0.055219 -0.425539 167 | v -0.214756 -0.014995 -0.374311 168 | v -0.176985 -0.015124 -0.425130 169 | v -0.227091 -0.043871 -0.308431 170 | v -0.229584 -0.043650 -0.250875 171 | v -0.177985 -0.075834 -0.246262 172 | v -0.201340 -0.070830 -0.270330 173 | v 0.215975 0.054756 0.201749 174 | v 0.216058 0.065555 0.270604 175 | v 0.130747 0.073971 0.079098 176 | v 0.154051 0.054750 0.064135 177 | v 0.117365 0.029066 0.274731 178 | v 0.112650 0.000764 0.268704 179 | v 0.112501 0.029427 0.214335 180 | v 0.104553 0.001720 0.211251 181 | v 0.119854 0.054039 0.314476 182 | v 0.139580 0.071459 0.324689 183 | v 0.137664 0.077821 0.381521 184 | v 0.134682 0.054062 0.246484 185 | v 0.157216 0.071046 0.245232 186 | v 0.072145 -0.052976 0.145240 187 | v 0.067260 -0.026653 0.159535 188 | v 0.016679 0.000263 0.144728 189 | v 0.069480 0.001467 0.166527 190 | v 0.078129 0.028679 0.165774 191 | v 0.055533 0.043972 0.142594 192 | v 0.114030 0.053191 0.183583 193 | v 0.132300 0.070511 0.172194 194 | v 0.066408 0.072769 0.112665 195 | v 0.182880 0.077035 0.246568 196 | v 0.198380 0.070615 0.206609 197 | v 0.109991 0.043758 0.462619 198 | v 0.086940 0.072150 0.443723 199 | v -0.143990 0.064253 0.061311 200 | v -0.162481 0.072128 0.141000 201 | v -0.070836 0.053288 0.144711 202 | v -0.103935 0.027092 0.203309 203 | v -0.064337 0.027059 0.158590 204 | v -0.085285 0.072778 0.126957 205 | v 0.130377 0.078643 -0.137373 206 | v 0.143990 0.064253 -0.061311 207 | v 0.162481 0.072128 -0.141000 208 | v 0.033931 -0.102736 0.021128 209 | v -0.013620 -0.092970 0.067033 210 | v -0.017420 -0.103765 0.019514 211 | v 0.144430 -0.063958 0.063078 212 | v 0.164735 -0.071550 0.145631 213 | v 0.039842 -0.043515 -0.372455 214 | v 0.043745 0.000113 -0.358932 215 | v 0.098774 0.028764 -0.320716 216 | v 0.011679 0.044474 -0.377875 217 | v 0.056461 0.043910 -0.365659 218 | v 0.016926 0.077778 -0.437286 219 | v 0.051474 0.071274 -0.403438 220 | v -0.144430 -0.063958 -0.063078 221 | v -0.164735 -0.071550 -0.145631 222 | v -0.039842 -0.043515 0.372455 223 | v -0.043745 0.000113 0.358932 224 | v -0.098774 0.028764 0.320716 225 | v -0.011679 0.044474 0.377875 226 | v -0.056461 0.043910 0.365659 227 | v -0.016926 0.077778 0.437286 228 | v -0.051474 0.071274 0.403438 229 | v 0.089422 0.084836 0.087783 230 | v 0.148983 0.077301 0.155338 231 | v -0.089422 0.084836 -0.087783 232 | v -0.148983 0.077301 -0.155338 233 | v 0.155013 -0.054050 -0.062498 234 | v 0.098521 -0.088093 0.058144 235 | v 0.109518 -0.080499 -0.003782 236 | v 0.135082 -0.071895 -0.082591 237 | v -0.040608 -0.001091 0.151679 238 | v -0.006474 0.027369 0.138989 239 | v -0.117240 0.027902 0.263865 240 | v -0.111172 -0.000862 0.238784 241 | v -0.108034 -0.015290 0.286318 242 | v -0.118081 -0.028990 0.243559 243 | v -0.096603 -0.029218 0.187188 244 | v -0.087620 -0.001514 0.185718 245 | v -0.049084 -0.028336 0.148599 246 | v 0.006940 -0.053514 0.124233 247 | v 0.009912 -0.027355 0.139023 248 | v -0.059559 -0.052588 0.136104 249 | v -0.069747 -0.071193 0.115051 250 | v 0.010884 -0.076074 0.101284 251 | v 0.064208 -0.075195 0.115066 252 | v 0.131198 -0.078763 0.139298 253 | v 0.078259 -0.088505 0.085363 254 | v -0.155013 -0.054050 0.062498 255 | v -0.056726 -0.095471 -0.060074 256 | v -0.131198 -0.078763 -0.139298 257 | v -0.111048 -0.071410 -0.151511 258 | v -0.098521 -0.088093 -0.058144 259 | v -0.109518 -0.080499 0.003782 260 | v -0.135082 -0.071895 0.082591 261 | v 0.103906 0.085665 -0.069889 262 | v 0.108709 0.081251 -0.005000 263 | v 0.034442 0.102371 0.021265 264 | v 0.075963 0.094600 0.013042 265 | v 0.013471 0.103828 -0.022416 266 | v -0.027796 0.100485 0.037640 267 | v -0.103906 0.085665 0.069889 268 | v -0.108709 0.081251 0.005000 269 | v -0.034442 0.102371 -0.021265 270 | v -0.075963 0.094600 -0.013042 271 | v 0.040608 -0.001091 -0.151679 272 | v 0.006474 0.027369 -0.138989 273 | v 0.064337 0.027059 -0.158590 274 | v 0.117240 0.027902 -0.263865 275 | v 0.103935 0.027092 -0.203309 276 | v 0.111172 -0.000862 -0.238784 277 | v 0.108034 -0.015290 -0.286318 278 | v 0.118081 -0.028990 -0.243559 279 | v 0.096603 -0.029218 -0.187188 280 | v 0.087620 -0.001514 -0.185718 281 | v 0.159791 -0.044092 -0.427265 282 | v 0.110272 -0.043635 -0.462468 283 | v 0.061774 -0.071645 -0.450800 284 | v 0.078724 -0.077581 -0.420633 285 | v 0.091129 0.000205 -0.322400 286 | v 0.091584 -0.028435 -0.330507 287 | v 0.139783 -0.071270 -0.324585 288 | v 0.119941 -0.053753 -0.314439 289 | v 0.134093 -0.053827 -0.246057 290 | v 0.156632 -0.071069 -0.245245 291 | v 0.059559 -0.052588 -0.136104 292 | v 0.049084 -0.028336 -0.148599 293 | v 0.112106 -0.053467 -0.182295 294 | v 0.130580 -0.070469 -0.170441 295 | v 0.214980 -0.054727 -0.199625 296 | v 0.197084 -0.070768 -0.204512 297 | v 0.013620 -0.092970 -0.067033 298 | v 0.024285 -0.100338 -0.035804 299 | v 0.107539 -0.079004 -0.102761 300 | v 0.084682 -0.089243 -0.045045 301 | v -0.159791 -0.044092 0.427265 302 | v -0.110272 -0.043635 0.462468 303 | v -0.061774 -0.071645 0.450800 304 | v -0.078724 -0.077581 0.420633 305 | v -0.091129 0.000205 0.322400 306 | v -0.091584 -0.028435 0.330507 307 | v -0.139783 -0.071270 0.324585 308 | v -0.119941 -0.053753 0.314439 309 | v -0.134093 -0.053827 0.246057 310 | v -0.156632 -0.071069 0.245245 311 | v -0.112106 -0.053467 0.182295 312 | v -0.130580 -0.070469 0.170441 313 | v -0.214980 -0.054727 0.199625 314 | v -0.197084 -0.070768 0.204512 315 | v -0.107539 -0.079004 0.102761 316 | v -0.084682 -0.089243 0.045045 317 | v -0.006757 0.053977 0.123829 318 | v -0.020415 0.076271 0.101549 319 | v -0.080278 0.085841 0.090316 320 | v -0.000654 0.092672 0.070206 321 | v 0.070836 0.053288 -0.144711 322 | v 0.085285 0.072778 -0.126957 323 | v 0.006757 0.053977 -0.123829 324 | v 0.020415 0.076271 -0.101549 325 | v 0.000654 0.092672 -0.070206 326 | v 0.080278 0.085841 -0.090316 327 | # 315 vertices, 0 vertices normals 328 | 329 | f 1 2 3 330 | f 4 2 1 331 | f 5 6 7 332 | f 8 6 5 333 | f 9 10 11 334 | f 12 13 10 335 | f 12 10 9 336 | f 9 14 12 337 | f 15 16 12 338 | f 13 16 17 339 | f 16 13 12 340 | f 14 15 12 341 | f 18 19 20 342 | f 21 22 19 343 | f 21 19 18 344 | f 18 23 21 345 | f 24 25 21 346 | f 22 25 26 347 | f 25 22 21 348 | f 23 24 21 349 | f 27 28 29 350 | f 30 28 27 351 | f 31 32 33 352 | f 6 33 7 353 | f 34 35 36 354 | f 37 35 34 355 | f 38 39 40 356 | f 2 40 3 357 | f 41 42 43 358 | f 44 45 46 359 | f 41 45 44 360 | f 47 48 49 361 | f 50 51 52 362 | f 47 51 50 363 | f 35 53 36 364 | f 53 35 54 365 | f 53 54 39 366 | f 55 53 39 367 | f 38 55 39 368 | f 38 56 57 369 | f 38 57 55 370 | f 58 59 60 371 | f 59 2 60 372 | f 59 58 56 373 | f 59 56 38 374 | f 40 59 38 375 | f 40 2 59 376 | f 61 60 62 377 | f 61 58 60 378 | f 63 2 4 379 | f 28 64 29 380 | f 64 28 65 381 | f 64 65 32 382 | f 66 64 32 383 | f 31 66 32 384 | f 31 67 68 385 | f 31 68 66 386 | f 69 70 71 387 | f 70 6 71 388 | f 70 69 67 389 | f 70 67 31 390 | f 33 70 31 391 | f 33 6 70 392 | f 72 71 73 393 | f 72 69 71 394 | f 74 75 76 395 | f 76 77 78 396 | f 77 76 75 397 | f 77 67 78 398 | f 68 67 77 399 | f 67 69 78 400 | f 79 80 72 401 | f 73 79 72 402 | f 76 78 80 403 | f 78 69 80 404 | f 80 69 72 405 | f 81 45 82 406 | f 45 41 82 407 | f 82 41 43 408 | f 79 83 84 409 | f 83 79 73 410 | f 46 83 73 411 | f 45 83 46 412 | f 84 83 81 413 | f 83 45 81 414 | f 85 86 87 415 | f 87 88 89 416 | f 88 87 86 417 | f 88 56 89 418 | f 57 56 88 419 | f 56 58 89 420 | f 90 91 61 421 | f 62 90 61 422 | f 87 89 91 423 | f 89 58 91 424 | f 91 58 61 425 | f 92 51 93 426 | f 51 47 93 427 | f 93 47 49 428 | f 90 94 95 429 | f 94 90 62 430 | f 52 94 62 431 | f 51 94 52 432 | f 95 94 92 433 | f 94 51 92 434 | f 96 97 98 435 | f 24 99 100 436 | f 100 37 34 437 | f 100 34 25 438 | f 100 25 24 439 | f 20 101 102 440 | f 103 18 102 441 | f 102 18 20 442 | f 23 18 103 443 | f 104 105 106 444 | f 104 106 23 445 | f 104 23 103 446 | f 105 107 106 447 | f 108 109 110 448 | f 100 111 112 449 | f 100 112 37 450 | f 99 111 100 451 | f 112 111 109 452 | f 37 112 109 453 | f 109 111 110 454 | f 113 114 115 455 | f 113 110 114 456 | f 114 110 111 457 | f 99 114 111 458 | f 43 42 115 459 | f 42 113 115 460 | f 116 24 23 461 | f 116 23 106 462 | f 115 117 43 463 | f 115 114 117 464 | f 114 99 117 465 | f 24 116 117 466 | f 99 24 117 467 | f 118 119 120 468 | f 121 48 122 469 | f 122 48 47 470 | f 123 118 120 471 | f 123 121 122 472 | f 123 120 121 473 | f 124 122 125 474 | f 122 47 125 475 | f 125 47 50 476 | f 11 126 127 477 | f 128 9 127 478 | f 127 9 11 479 | f 14 9 128 480 | f 129 130 131 481 | f 129 131 14 482 | f 129 14 128 483 | f 132 133 127 484 | f 133 130 129 485 | f 128 133 129 486 | f 133 128 127 487 | f 134 135 132 488 | f 133 135 130 489 | f 135 133 132 490 | f 136 132 127 491 | f 136 126 137 492 | f 126 138 137 493 | f 136 127 126 494 | f 139 137 140 495 | f 139 134 132 496 | f 139 132 136 497 | f 139 136 137 498 | f 137 138 140 499 | f 141 142 96 500 | f 141 96 98 501 | f 141 130 142 502 | f 130 135 142 503 | f 143 144 145 504 | f 145 144 134 505 | f 144 143 96 506 | f 144 96 142 507 | f 135 144 142 508 | f 144 135 134 509 | f 146 143 145 510 | f 147 140 148 511 | f 146 147 148 512 | f 146 148 149 513 | f 146 145 147 514 | f 147 145 134 515 | f 147 134 139 516 | f 140 147 139 517 | f 140 150 148 518 | f 138 150 140 519 | f 150 138 118 520 | f 150 118 123 521 | f 151 150 123 522 | f 123 122 151 523 | f 122 124 151 524 | f 65 28 152 525 | f 28 30 152 526 | f 152 119 153 527 | f 30 119 152 528 | f 119 118 153 529 | f 118 138 153 530 | f 152 153 65 531 | f 65 153 32 532 | f 15 154 155 533 | f 155 30 27 534 | f 155 27 16 535 | f 155 16 15 536 | f 155 156 157 537 | f 155 157 30 538 | f 154 156 155 539 | f 157 156 119 540 | f 30 157 119 541 | f 119 156 120 542 | f 121 158 159 543 | f 49 48 159 544 | f 48 121 159 545 | f 121 120 158 546 | f 158 120 156 547 | f 154 158 156 548 | f 160 15 14 549 | f 160 14 131 550 | f 159 161 49 551 | f 159 158 161 552 | f 158 154 161 553 | f 15 160 161 554 | f 154 15 161 555 | f 113 42 162 556 | f 162 42 41 557 | f 163 108 110 558 | f 163 113 162 559 | f 163 110 113 560 | f 164 162 165 561 | f 162 41 165 562 | f 165 41 44 563 | f 166 167 102 564 | f 167 105 104 565 | f 103 167 104 566 | f 167 103 102 567 | f 168 169 166 568 | f 167 169 105 569 | f 169 167 166 570 | f 170 166 102 571 | f 170 101 171 572 | f 101 172 171 573 | f 170 102 101 574 | f 173 171 174 575 | f 173 168 166 576 | f 173 166 170 577 | f 173 170 171 578 | f 171 172 174 579 | f 175 105 176 580 | f 107 105 175 581 | f 105 169 176 582 | f 177 178 179 583 | f 179 178 168 584 | f 169 178 176 585 | f 178 169 168 586 | f 180 177 179 587 | f 181 174 182 588 | f 180 181 182 589 | f 180 182 183 590 | f 180 179 181 591 | f 181 179 168 592 | f 181 168 173 593 | f 174 181 173 594 | f 174 184 182 595 | f 172 184 174 596 | f 184 172 108 597 | f 184 108 163 598 | f 185 184 163 599 | f 163 162 185 600 | f 162 164 185 601 | f 54 35 186 602 | f 35 37 186 603 | f 186 109 187 604 | f 37 109 186 605 | f 109 108 187 606 | f 108 172 187 607 | f 186 187 54 608 | f 54 187 39 609 | f 188 50 52 610 | f 62 189 188 611 | f 52 62 188 612 | f 60 189 62 613 | f 2 189 60 614 | f 2 63 189 615 | f 190 191 192 616 | f 193 4 190 617 | f 4 191 190 618 | f 193 63 4 619 | f 194 6 8 620 | f 195 44 46 621 | f 73 196 195 622 | f 46 73 195 623 | f 71 196 73 624 | f 6 196 71 625 | f 6 194 196 626 | f 197 198 199 627 | f 200 81 82 628 | f 43 201 200 629 | f 82 43 200 630 | f 117 201 43 631 | f 116 201 117 632 | f 202 203 10 633 | f 13 202 10 634 | f 202 13 17 635 | f 7 204 5 636 | f 205 10 206 637 | f 11 10 205 638 | f 10 203 206 639 | f 203 204 206 640 | f 206 204 7 641 | f 33 207 208 642 | f 32 207 33 643 | f 153 207 32 644 | f 138 207 153 645 | f 208 207 126 646 | f 207 138 126 647 | f 11 208 126 648 | f 205 208 11 649 | f 208 205 206 650 | f 206 7 208 651 | f 7 33 208 652 | f 209 92 93 653 | f 49 210 209 654 | f 93 49 209 655 | f 161 210 49 656 | f 160 210 161 657 | f 211 212 19 658 | f 22 211 19 659 | f 211 22 26 660 | f 3 213 1 661 | f 214 19 215 662 | f 20 19 214 663 | f 19 212 215 664 | f 212 213 215 665 | f 215 213 3 666 | f 40 216 217 667 | f 39 216 40 668 | f 187 216 39 669 | f 172 216 187 670 | f 217 216 101 671 | f 216 172 101 672 | f 20 217 101 673 | f 214 217 20 674 | f 217 214 215 675 | f 215 3 217 676 | f 3 40 217 677 | f 218 219 164 678 | f 219 218 183 679 | f 182 219 183 680 | f 184 219 182 681 | f 219 184 185 682 | f 164 219 185 683 | f 220 221 124 684 | f 221 220 149 685 | f 148 221 149 686 | f 150 221 148 687 | f 221 150 151 688 | f 124 221 151 689 | f 222 84 81 690 | f 200 223 224 691 | f 225 222 224 692 | f 224 222 81 693 | f 200 224 81 694 | f 200 201 223 695 | f 226 227 192 696 | f 226 177 227 697 | f 227 177 180 698 | f 228 191 4 699 | f 1 228 4 700 | f 1 213 228 701 | f 229 191 228 702 | f 229 230 231 703 | f 230 229 228 704 | f 232 233 231 705 | f 226 233 232 706 | f 233 226 192 707 | f 191 233 192 708 | f 229 233 191 709 | f 233 229 231 710 | f 177 226 234 711 | f 226 232 234 712 | f 235 236 237 713 | f 238 235 237 714 | f 176 236 235 715 | f 175 176 235 716 | f 178 236 176 717 | f 178 177 236 718 | f 236 177 234 719 | f 237 236 234 720 | f 235 238 239 721 | f 239 198 240 722 | f 238 198 239 723 | f 175 239 240 724 | f 175 235 239 725 | f 240 107 175 726 | f 241 242 223 727 | f 201 241 223 728 | f 116 241 201 729 | f 241 116 106 730 | f 242 241 107 731 | f 107 241 106 732 | f 242 107 240 733 | f 198 242 240 734 | f 242 198 197 735 | f 223 242 197 736 | f 243 95 92 737 | f 244 245 246 738 | f 246 245 131 739 | f 160 245 210 740 | f 245 160 131 741 | f 130 246 131 742 | f 246 130 141 743 | f 98 246 141 744 | f 244 246 98 745 | f 209 247 248 746 | f 249 243 248 747 | f 248 243 92 748 | f 209 248 92 749 | f 209 210 247 750 | f 210 245 247 751 | f 245 244 247 752 | f 199 247 244 753 | f 195 250 251 754 | f 164 165 251 755 | f 251 165 44 756 | f 195 251 44 757 | f 195 196 250 758 | f 196 194 250 759 | f 252 218 253 760 | f 218 164 253 761 | f 253 164 251 762 | f 250 253 251 763 | f 253 254 252 764 | f 253 250 254 765 | f 252 254 255 766 | f 188 256 257 767 | f 124 125 257 768 | f 257 125 50 769 | f 188 257 50 770 | f 188 189 256 771 | f 189 63 256 772 | f 258 220 259 773 | f 259 255 258 774 | f 220 124 259 775 | f 259 124 257 776 | f 256 259 257 777 | f 259 256 255 778 | f 255 254 258 779 | f 260 261 262 780 | f 260 143 261 781 | f 261 143 146 782 | f 263 264 8 783 | f 5 263 8 784 | f 5 204 263 785 | f 265 264 263 786 | f 265 266 267 787 | f 266 265 263 788 | f 268 269 267 789 | f 260 269 268 790 | f 269 260 262 791 | f 264 269 262 792 | f 265 269 264 793 | f 269 265 267 794 | f 66 270 271 795 | f 29 64 271 796 | f 64 66 271 797 | f 66 68 270 798 | f 270 68 77 799 | f 271 270 75 800 | f 77 75 270 801 | f 272 27 29 802 | f 271 272 29 803 | f 75 273 272 804 | f 271 75 272 805 | f 272 273 16 806 | f 27 272 16 807 | f 16 273 17 808 | f 266 274 275 809 | f 274 266 263 810 | f 204 274 263 811 | f 203 274 204 812 | f 275 274 202 813 | f 202 17 275 814 | f 274 203 202 815 | f 273 75 276 816 | f 267 266 277 817 | f 277 266 275 818 | f 277 17 276 819 | f 17 273 276 820 | f 277 275 17 821 | f 278 276 279 822 | f 278 268 267 823 | f 278 267 277 824 | f 278 277 276 825 | f 276 75 279 826 | f 75 74 279 827 | f 280 96 281 828 | f 97 96 280 829 | f 96 143 281 830 | f 143 260 281 831 | f 260 268 281 832 | f 282 279 283 833 | f 279 74 283 834 | f 280 282 283 835 | f 280 283 97 836 | f 280 281 282 837 | f 281 268 282 838 | f 282 268 278 839 | f 279 282 278 840 | f 76 284 285 841 | f 285 74 76 842 | f 76 80 284 843 | f 80 79 284 844 | f 284 79 84 845 | f 284 225 285 846 | f 284 84 222 847 | f 225 284 222 848 | f 244 286 287 849 | f 199 287 197 850 | f 199 244 287 851 | f 286 244 98 852 | f 97 286 98 853 | f 288 225 289 854 | f 283 288 97 855 | f 74 288 283 856 | f 288 74 285 857 | f 225 288 285 858 | f 289 225 224 859 | f 223 289 224 860 | f 289 223 197 861 | f 287 289 197 862 | f 288 289 286 863 | f 288 286 97 864 | f 286 289 287 865 | f 55 290 291 866 | f 36 53 291 867 | f 53 55 291 868 | f 55 57 290 869 | f 290 57 88 870 | f 291 290 86 871 | f 88 86 290 872 | f 292 34 36 873 | f 291 292 36 874 | f 86 293 292 875 | f 291 86 292 876 | f 292 293 25 877 | f 34 292 25 878 | f 25 293 26 879 | f 230 294 295 880 | f 294 230 228 881 | f 213 294 228 882 | f 212 294 213 883 | f 295 294 211 884 | f 211 26 295 885 | f 294 212 211 886 | f 293 86 296 887 | f 231 230 297 888 | f 297 230 295 889 | f 297 26 296 890 | f 26 293 296 891 | f 297 295 26 892 | f 298 296 299 893 | f 298 232 231 894 | f 298 231 297 895 | f 298 297 296 896 | f 296 86 299 897 | f 86 85 299 898 | f 300 299 301 899 | f 299 85 301 900 | f 237 300 301 901 | f 237 301 238 902 | f 237 234 300 903 | f 234 232 300 904 | f 300 232 298 905 | f 299 300 298 906 | f 87 302 303 907 | f 303 85 87 908 | f 87 91 302 909 | f 91 90 302 910 | f 302 90 95 911 | f 302 249 303 912 | f 302 95 243 913 | f 249 302 243 914 | f 304 249 305 915 | f 304 305 198 916 | f 304 198 238 917 | f 301 304 238 918 | f 85 304 301 919 | f 304 85 303 920 | f 249 304 303 921 | f 305 249 248 922 | f 247 305 248 923 | f 305 247 199 924 | f 198 305 199 925 | f 306 183 307 926 | f 190 306 307 927 | f 190 307 193 928 | f 190 192 306 929 | f 192 227 306 930 | f 306 227 180 931 | f 183 306 180 932 | f 308 309 255 933 | f 309 308 307 934 | f 256 308 255 935 | f 63 308 256 936 | f 308 63 193 937 | f 307 308 193 938 | f 183 309 307 939 | f 218 309 183 940 | f 218 252 309 941 | f 309 252 255 942 | f 310 264 262 943 | f 311 8 310 944 | f 8 264 310 945 | f 311 194 8 946 | f 312 149 313 947 | f 310 312 313 948 | f 310 313 311 949 | f 310 262 312 950 | f 262 261 312 951 | f 312 261 146 952 | f 149 312 146 953 | f 314 315 313 954 | f 194 315 250 955 | f 315 194 311 956 | f 313 315 311 957 | f 149 314 313 958 | f 220 314 149 959 | f 220 258 314 960 | f 315 314 254 961 | f 250 315 254 962 | f 314 258 254 963 | # 634 faces, 0 coords texture 964 | 965 | # End of File --------------------------------------------------------------------------------