├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── Options.cpp ├── Options.h ├── README.md ├── TM2IN.cpp ├── algorithm ├── Polygonizer.cpp ├── Polygonizer.h ├── collinear.cpp ├── collinear.h ├── compare.cpp ├── compare.h ├── mbb.cpp ├── mbb.h ├── merge_surfaces.cpp ├── merge_surfaces.h ├── triangulation.cpp └── triangulation.h ├── cgal ├── polyhedron.cpp ├── polyhedron.h ├── triangle.cpp ├── triangle.h ├── vector_angle.cpp └── vector_angle.h ├── compute ├── unused.cpp └── unused.h ├── config.h ├── converter ├── Converter.cpp ├── Converter.h ├── run.cpp └── start.cpp ├── detail ├── algorithm │ ├── merge_surfaces.cpp │ ├── merge_surfaces.h │ ├── self_intersect.cpp │ ├── self_intersect.h │ ├── simplify_share_edges.cpp │ ├── simplify_share_edges.h │ ├── surface_neighbor.cpp │ ├── surface_neighbor.h │ ├── triangulate_surface.cpp │ └── triangulate_surface.h ├── cgal │ ├── geometry.cpp │ ├── geometry.h │ ├── plane.cpp │ ├── plane.h │ ├── polygon.cpp │ ├── polygon.h │ ├── type_conversion.cpp │ ├── type_conversion.h │ ├── vector_3.cpp │ └── vector_3.h ├── cgal_config.h ├── features │ ├── RoomFactory.cpp │ ├── RoomFactory.h │ ├── halfedge_string.cpp │ └── halfedge_string.h └── io │ ├── ColladaReader.cpp │ ├── ColladaReader.h │ ├── InFactoryClient.cpp │ ├── InFactoryClient.h │ ├── IndoorGMLWriter.cpp │ ├── IndoorGMLWriter.h │ ├── JsonWriter.cpp │ ├── JsonWriter.h │ ├── Max3DSReader.cpp │ ├── Max3DSReader.h │ ├── Max3DSWriter.cpp │ ├── Max3DSWriter.h │ ├── TVRReader.cpp │ └── TVRReader.h ├── doc ├── Doxyfile ├── img │ ├── 180920-tm2in-process.gif │ └── pipeline.png ├── mainpage.h └── usage-manual.md ├── features ├── HalfEdge.cpp ├── HalfEdge.h ├── IndoorComponent.cpp ├── IndoorComponent.h ├── MinimumBoundingBox.cpp ├── MinimumBoundingBox.h ├── Room.cpp ├── Room.h ├── RoomBoundary │ ├── PolygonMesh.cpp │ ├── PolygonMesh.h │ ├── TriangleMesh.cpp │ ├── TriangleMesh.h │ ├── TriangulatedSurfaceMesh.cpp │ └── TriangulatedSurfaceMesh.h ├── Vertex.cpp ├── Vertex.h └── Wall │ ├── Polygon.cpp │ ├── Polygon.h │ ├── Surface.cpp │ ├── Surface.h │ ├── Triangle.cpp │ ├── Triangle.h │ ├── TriangulatedSurface.cpp │ └── TriangulatedSurface.h ├── io ├── GenerationWriter.cpp ├── GenerationWriter.h ├── json.cpp ├── json.h ├── max3ds.cpp ├── max3ds.h ├── tvr.cpp ├── tvr.h ├── xml.cpp └── xml.h ├── util.cpp └── util.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | *.xcodeproj 3 | DerivedData/ 4 | 5 | # Code Blocks 6 | *.cbp 7 | *.depend 8 | *.layout 9 | bin/ 10 | obj/ 11 | cscope.out 12 | *.cscope_file_list 13 | 14 | # clion 15 | .idea/ 16 | cmake-build-debug 17 | 18 | # develop 19 | cleaner.cpp 20 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.9) 2 | project(TM2IN) 3 | 4 | set(CMAKE_CXX_STANDARD 11) 5 | 6 | # set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") 7 | 8 | set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/Modules;${CMAKE_MODULE_PATH}" ) 9 | 10 | find_package(CGAL REQUIRED ) 11 | 12 | if ( CGAL_FOUND ) 13 | include( ${CGAL_USE_FILE} ) 14 | include( CGAL_CreateSingleSourceCGALProgram ) 15 | endif() 16 | if ( NOT CGAL_FOUND ) 17 | message(STATUS "This project requires the CGAL library, and will not be compiled.") 18 | return() 19 | endif() 20 | 21 | FIND_PACKAGE( Boost 1.40 REQUIRED COMPONENTS filesystem REQUIRED ) 22 | INCLUDE_DIRECTORIES( ${Boost_INCLUDE_DIR} ) 23 | 24 | find_package(Eigen3 3.3 REQUIRED NO_MODULE) 25 | find_package(CURL REQUIRED) 26 | 27 | file(GLOB DETAIL_FILES 28 | "detail/io/*.h" 29 | "detail/io/*.cpp" 30 | "detail/cgal/*.h" 31 | "detail/cgal/*.cpp" 32 | "detail/cgal_config.h" 33 | "detail/algorithm/*.h" 34 | "detail/algorithm/*.cpp" 35 | "detail/features/*.h" 36 | "detail/features/*.cpp" 37 | ) 38 | 39 | file(GLOB FEATURES_FILES 40 | "features/RoomBoundary/*.h" 41 | "features/RoomBoundary/*.cpp" 42 | "features/Wall/*.h" 43 | "features/Wall/*.cpp" 44 | "features/HalfEdge.h" 45 | "features/HalfEdge.cpp" 46 | "features/IndoorComponent.cpp" 47 | "features/IndoorComponent.h" 48 | "features/Room.h" 49 | "features/Room.cpp" 50 | "features/Vertex.h" 51 | "features/Vertex.cpp" 52 | "features/MinimumBoundingBox.cpp" 53 | "features/MinimumBoundingBox.h" 54 | ) 55 | 56 | file(GLOB SOURCE_FILES 57 | "io/*.h" 58 | "io/*.cpp" 59 | "cgal/*.h" 60 | "cgal/*.cpp" 61 | "compute/*.h" 62 | "compute/*.cpp" 63 | "converter/*.h" 64 | "converter/*.cpp" 65 | "algorithm/*.h" 66 | "algorithm/*.cpp" 67 | config.h 68 | util.cpp 69 | util.h 70 | ) 71 | 72 | add_executable(TM2IN 73 | ${SOURCE_FILES} 74 | ${DETAIL_FILES} 75 | ${FEATURES_FILES} 76 | Options.h 77 | Options.cpp 78 | TM2IN.cpp) 79 | 80 | TARGET_LINK_LIBRARIES(TM2IN LINK_PUBLIC ${Boost_LIBRARIES} Eigen3::Eigen restclient-cpp ${CURL_LIBRARIES} 81 | ) 82 | 83 | include_directories( 84 | .) 85 | 86 | -------------------------------------------------------------------------------- /Options.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 17. 3 | // 4 | 5 | #include "Options.h" 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | Options* Options::instance = NULL; 12 | 13 | void Options::make_file_name(){ 14 | if (!has_input_type){ 15 | string file_extension = input_file.substr(input_file.find_last_of(".") + 1); 16 | if (file_extension == "tvr" || file_extension == "TVR"){ 17 | input_type = 1; 18 | } 19 | else if (file_extension == "3ds" || file_extension == "3DS"){ 20 | input_type = 2; 21 | } 22 | else if (file_extension == "dae" || file_extension == "DAE"){ 23 | input_type = 3; 24 | } 25 | } 26 | 27 | std::size_t pos = input_file.find_last_of("."); 28 | file_name = input_file.substr(0, pos); 29 | fprintf(stdout, "File name : %s\n",file_name.c_str()); 30 | 31 | output_dir += file_name; 32 | output_dir += "/"; 33 | output_dir += version; 34 | output_dir += "/"; 35 | } 36 | 37 | void Options::check_options() { 38 | if (!has_input_dir){ 39 | throw std::runtime_error("--input-dir is missing..;\n"); 40 | } 41 | 42 | if (!has_output_dir){ 43 | throw std::runtime_error("--output-dir missing : where can I store..\n"); 44 | } 45 | 46 | if (!has_input_type){ 47 | fprintf(stderr, "WARNING : we will detect your file type and covert. Maybe it will be right..\n"); 48 | fprintf(stderr, "IF you can make it sure, define value of --input-type option.\n\n"); 49 | } 50 | } 51 | 52 | void Options::make(int argc, char **argv) { 53 | const char *short_opts = "i:O:v:r:tp:a:b:TDLI:GA:VC"; 54 | const option long_opts[] = { 55 | {"input-dir", 1, 0, 'i'}, 56 | {"output-dir", 1, 0, 'O'}, 57 | {"version", 1, 0, 'v'}, 58 | {"input-type", 1, 0, 'r'}, 59 | {"no-merge", 0, 0, 't'}, 60 | {"polygonizer", 1, 0, 'p'}, 61 | {"thres1" , 1, 0, 'a'}, 62 | {"thres2", 1, 0, 'b'}, 63 | {"output-tvr", 0, 0, 'T'}, 64 | {"output-3ds", 0, 0, 'D'}, 65 | {"output-tri", 0, 0, 'L'}, 66 | {"indoorGML" , 1, 0, 'I'}, 67 | {"write-process",0,0, 'G'}, 68 | {"select-arch", 1, 0, 'A'}, 69 | {"do-validation", 0, 0, 'V'}, 70 | {"do-classification", 0, 0, 'C'}, 71 | {0, 0, 0, 0} 72 | }; 73 | int index = 0; 74 | int c; 75 | while (-1 != (c = getopt_long(argc, argv, short_opts, long_opts, &index))){ 76 | string type_name; 77 | switch (c){ 78 | case 'i': 79 | assert(optarg != NULL); 80 | input_dir = optarg; 81 | if (input_dir.back() != '/'){ 82 | input_dir.append("/"); 83 | } 84 | has_input_dir = true; 85 | break; 86 | case 'O': 87 | assert(optarg != NULL); 88 | output_dir = optarg; 89 | if (output_dir.back() != '/'){ 90 | output_dir.append("/"); 91 | } 92 | has_output_dir = true; 93 | break; 94 | case 'r': 95 | assert(optarg != NULL); 96 | type_name = optarg; 97 | has_input_type = true; 98 | if (type_name == "tvr" || type_name == "TVR"){ 99 | input_type = 1; 100 | } 101 | else if (type_name == "3ds" || type_name == "3DS"){ 102 | input_type = 2; 103 | } 104 | else if (type_name == "dae" || type_name == "DAE" || type_name == "collada" || type_name == "COLLADA"){ 105 | input_type = 3; 106 | } 107 | else{ 108 | printf("\n"); 109 | printf("Import mode should be one type of {tvr, 3ds, collada}"); 110 | printf("\n"); 111 | } 112 | break; 113 | case 'v': 114 | version = optarg; 115 | break; 116 | case 't': 117 | has_no_merge = true; 118 | break; 119 | case 'p': 120 | has_polygonizer = true; 121 | polygonizer_mode = stoi(optarg); 122 | break; 123 | case 'a': 124 | assert(optarg != NULL); 125 | threshold_1 = strtod(optarg, NULL); 126 | break; 127 | case 'b': 128 | assert(optarg != NULL); 129 | threshold_2 = strtod(optarg, NULL); 130 | break; 131 | case 'T': 132 | break; 133 | case 'D': 134 | break; 135 | case 'G': 136 | generator = true; 137 | break; 138 | case 'A': 139 | assert(optarg != NULL); 140 | selected = stoi(optarg); 141 | break; 142 | case 'L': 143 | break; 144 | case 'V': 145 | do_validation = 1; 146 | break; 147 | case 'I': 148 | output_indoor_gml = true; 149 | infactory_url = optarg; 150 | break; 151 | case 'C': 152 | do_classification = true; 153 | break; 154 | } 155 | } 156 | 157 | if (optind < argc) 158 | { 159 | input_file = argv[optind++]; 160 | } 161 | else{ 162 | fprintf(stderr, "There is no input file name..\n"); 163 | exit(EXIT_FAILURE); 164 | } 165 | 166 | if (optind < argc){ 167 | fprintf(stderr, "Only one file is needed\n"); 168 | } 169 | 170 | check_options(); 171 | make_file_name(); 172 | } 173 | 174 | 175 | -------------------------------------------------------------------------------- /Options.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 17. 3 | // 4 | 5 | #ifndef TM2IN_OPTIONS_H 6 | #define TM2IN_OPTIONS_H 7 | 8 | #include 9 | #include 10 | #include "config.h" 11 | 12 | using namespace std; 13 | 14 | enum ARCHITECTURE {ARCH, NON_ARCH, ALL, MANUAL}; 15 | 16 | class Options { 17 | private: 18 | Options(){} 19 | 20 | static Options* instance; 21 | public: 22 | static Options* getInstance(){ 23 | if(!instance){ 24 | instance = new Options(); 25 | } 26 | return instance; 27 | } 28 | 29 | void make(int argc, char **argv); 30 | 31 | string input_dir; 32 | string output_dir; 33 | 34 | string input_file; // "apt3.tvr" 35 | string output_file; // "ap3.json" 36 | 37 | string file_name; 38 | string version; // "x.y.z" 39 | 40 | double threshold_1 = 1.0; 41 | double threshold_2 = 10.0; 42 | 43 | int input_type = 0; 44 | int polygonizer_mode = 0; // 1 : PCA Polygonize, 2 : Triangle Polygonize, 3 : Divided Polygonize 45 | 46 | bool output_3ds = false; 47 | bool output_tvr = false; 48 | bool output_indoor_gml = false; 49 | string infactory_url; 50 | 51 | bool generator = false; 52 | int generation = 0; 53 | 54 | int selected = ARCH; 55 | int do_validation = 0; 56 | bool has_no_merge = false; 57 | bool do_classification = false; 58 | 59 | private: 60 | bool has_input_dir = false; 61 | bool has_output_dir = false; 62 | bool has_version = false; 63 | bool has_input_type = false; 64 | bool has_polygonizer = false; 65 | 66 | void check_options(); 67 | 68 | void make_file_name(); 69 | }; 70 | 71 | 72 | #endif //TM2IN_OPTIONS_H 73 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TM2IN 2 | TM2IN(Triangle Mesh to Indoor data) is a project which converts indoor spatial standard data from raw indoor geometry data, like triangle mesh or point cloud. 3 | TM2IN not only constructs indoor spatial standard data but also refines geometry data by removing unnecessary elements and reducing the number of surfaces. 4 | 5 | The following image is available from [TM2IN-Viewer](https://github.com/cocoslime/TM2IN-Viewer). 6 | 7 | ![](doc/img/180920-tm2in-process.gif) 8 | 9 | ## Pipeline 10 | 11 | ![](doc/img/pipeline.png?raw=true) 12 | 13 | ## Author 14 | Dongmin Kim(dongmin.kim@pnu.edu), Pusan National University 15 | 16 | ## Dependencies 17 | 18 | - CGAL (http://www.cgal.org/) 19 | - Eigen3 (http://eigen.tuxfamily.org/index.php?title=Main_Page) 20 | - Boost (http://www.boost.org/) 21 | - rapidxml (http://rapidxml.sourceforge.net) : To read COLLADA(*.dae) file 22 | - libcurl (https://curl.haxx.se/libcurl/c/libcurl.html) 23 | - InFactory (https://github.com/STEMLab/InFactory) : To generate IndoorGML 24 | 25 | ## Supported Platform 26 | - Linux 27 | 28 | ## Building 29 | 30 | Dependencies should be pre-installed in your environment. 31 | 32 | ``` 33 | git clone https://github.com/STEMLab/TM2IN 34 | mkdir build 35 | cd build 36 | cmake .. 37 | make 38 | ``` 39 | 40 | ## Usage 41 | 42 | ``` 43 | TM2IN [options] [input_file_name] 44 | 45 | ``` 46 | 47 | For example, 48 | 49 | ``` 50 | TM2IN --input-dir=../../input/ --output-dir=../../result --version=0.4.2 inputfile.tvr 51 | ``` 52 | 53 | 54 | There are more information about options. (http://github.com/STEMLab/TM2IN/tree/master/doc/usage-manual.md) 55 | 56 | ## Development 57 | 58 | For Developer, we document source code description. see : [MANUAL](http://STEMLab.github.io/TM2IN/doxygen/index.html) 59 | -------------------------------------------------------------------------------- /TM2IN.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "converter/Converter.h" 3 | #include "Options.h" 4 | 5 | using namespace std; 6 | 7 | int main(int argc, char * argv[]) { 8 | try{ 9 | Options* opt = Options::getInstance(); 10 | opt->make(argc, argv); 11 | createAndRemoveDir(); 12 | 13 | Converter converter = Converter(); 14 | converter.start(); 15 | 16 | converter.run(); 17 | 18 | converter.finish(); 19 | } 20 | catch(const std::runtime_error& e){ 21 | fprintf(stderr, "TM2IN : %s\n", e.what()); 22 | exit(EXIT_FAILURE); 23 | } 24 | return 0; 25 | } 26 | 27 | -------------------------------------------------------------------------------- /algorithm/Polygonizer.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 19. 3 | // 4 | 5 | #include "Polygonizer.h" 6 | 7 | #include 8 | 9 | #include "features/Wall/Triangle.h" 10 | #include "features/Wall/TriangulatedSurface.h" 11 | #include "features/Wall/Polygon.h" 12 | #include "features/Vertex.h" 13 | #include "detail/cgal/plane.h" 14 | #include "algorithm/merge_surfaces.h" 15 | #include "features/RoomBoundary/PolygonMesh.h" 16 | 17 | namespace TM2IN{ 18 | namespace algorithm{ 19 | TM2IN::RoomBoundary::PolygonMesh* TrianglePolygonizer::run(TM2IN::RoomBoundary::TSM *space) { 20 | cout << "===== Run Triangle Polygonizer =====" << endl; 21 | vector triangleList; 22 | for (unsigned int sfID = 0 ; sfID < space->surfaces.size(); sfID++) { 23 | TM2IN::Wall::TriangulatedSurface* pSurface = space->surfaces[sfID]; 24 | vector triangulation = pSurface->getTriangulation(); 25 | for (auto tri : triangulation){ 26 | tri->surface_type = pSurface->surface_type; 27 | } 28 | triangleList.insert(triangleList.end(),triangulation.begin(),triangulation.end()); 29 | } 30 | 31 | vector newSurfaceList; 32 | for (int i = 0 ; i < triangleList.size() ; i++){ 33 | newSurfaceList.push_back(new Polygon(triangleList[i])); 34 | } 35 | 36 | TM2IN::RoomBoundary::PolygonMesh* pm = new TM2IN::RoomBoundary::PolygonMesh(newSurfaceList); 37 | return pm; 38 | //space->surfaces = newSurfaceList; 39 | } 40 | 41 | TM2IN::RoomBoundary::PolygonMesh* DividedPolygonizer::run(TM2IN::RoomBoundary::TSM *space) { 42 | cout << "===== Run Divided Polygonizer =====" << endl; 43 | double thres1 = 1.0; 44 | double thres2 = 45.0; 45 | vector newSurfaceList; 46 | for (int i = 0 ; i < space->surfaces.size() ; i++){ 47 | TM2IN::Wall::TriangulatedSurface* sf = space->surfaces[i]; 48 | vector newSurfacesInSurface; 49 | vector triangulation = sf->getTriangulation(); 50 | for (auto tri : triangulation){ 51 | tri->surface_type = sf->surface_type; 52 | } 53 | 54 | TM2IN::detail::HalfEdgeString::connectOppositeHalfEdges(triangulation); 55 | TM2IN::algorithm::mergeTriangles(triangulation, thres1, thres2, newSurfacesInSurface); 56 | newSurfaceList.insert(newSurfaceList.end(), newSurfacesInSurface.begin(), newSurfacesInSurface.end()); 57 | } 58 | 59 | vector newPolygonList; 60 | for (int i = 0 ; i < newSurfaceList.size() ; i++){ 61 | newPolygonList.push_back(new Polygon(newSurfaceList[i])); 62 | } 63 | 64 | TM2IN::RoomBoundary::PolygonMesh* pm = new TM2IN::RoomBoundary::PolygonMesh(newPolygonList); 65 | return pm; 66 | } 67 | 68 | 69 | TM2IN::RoomBoundary::PolygonMesh* PCAPolygonizer::run(TM2IN::RoomBoundary::TSM *space) { 70 | vector newPolygonList; 71 | for (unsigned int sfID = 0 ; sfID < space->surfaces.size(); sfID++) { 72 | Surface* sf = space->surfaces[sfID]; 73 | vector vertices = sf->getVerticesList(); 74 | Plane_3 plane = TM2IN::detail::cgal::make_PCA_plane(vertices, sf->normal); 75 | 76 | vector newVertices; 77 | for (ull index = 0 ; index < vertices.size() ; index++ ) 78 | { 79 | Point_3 point = vertices[index]->CGAL_point(); 80 | Point_3 projected = plane.projection(point); 81 | auto vt = new Vertex(projected.x(), projected.y(), projected.z()); 82 | vt->geom_id = "0"; 83 | newVertices.push_back(vt); 84 | } 85 | assert(newVertices.size() == sf->getVerticesSize()); 86 | 87 | TM2IN::Wall::Polygon* new_sf = new TM2IN::Wall::Polygon(newVertices); 88 | new_sf->surface_type = sf->surface_type; 89 | new_sf->normal = plane.orthogonal_vector(); 90 | newPolygonList.push_back(new_sf); 91 | } 92 | TM2IN::RoomBoundary::PolygonMesh* pm = new TM2IN::RoomBoundary::PolygonMesh(newPolygonList); 93 | return pm; 94 | } 95 | 96 | 97 | void PCAPolygonizer::scale_up(vector &vertices, double scale){ 98 | // translate to 0, 0 99 | double center[3] ={0}; 100 | for (ull index = 0 ; index < vertices.size() ; index++){ 101 | center[0] += vertices[index]->x(); 102 | center[1] += vertices[index]->y(); 103 | center[2] += vertices[index]->z(); 104 | } 105 | 106 | center[0] /= (double)vertices.size(); 107 | center[1] /= (double)vertices.size(); 108 | center[2] /= (double)vertices.size(); 109 | 110 | double diff[3] = {-center[0], -center[1], -center[2]}; 111 | 112 | for (ull index = 0 ; index < vertices.size() ; index++){ 113 | vertices[index]->translate(diff); 114 | vector dest_vec = {vertices[index]->x() * scale, vertices[index]->y() * scale, vertices[index]->z() * scale}; 115 | vertices[index]->translateTo(dest_vec); 116 | vertices[index]->translate(center); 117 | } 118 | } 119 | /* 120 | SFCGAL::Polygon PCAPolygonizer::make_sf_polygon(vector vertices) { 121 | vector sf_points; 122 | for (ull index = 0 ; index < vertices.size() ; index++) { 123 | SFCGAL::Coordinate coord(vertices[index]->x(), vertices[index]->y(), vertices[index]->z()); 124 | sf_points.push_back(SFCGAL::Point(coord)); 125 | } 126 | SFCGAL::LineString sf_ls(sf_points); 127 | SFCGAL::Polygon sf_pl(sf_ls); 128 | return sf_pl; 129 | } 130 | */ 131 | } 132 | } -------------------------------------------------------------------------------- /algorithm/Polygonizer.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 19. 3 | // 4 | 5 | #ifndef TM2IN_POLYGONIZER_H 6 | #define TM2IN_POLYGONIZER_H 7 | 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | namespace TM2IN { 14 | namespace algorithm { 15 | /** 16 | * @ingroup public_api 17 | * @brief Converter TM2IN::RoomBoundary::TriangulatedSurfaceMesh to TM2IN::RoomBoundary::PolygonMesh 18 | */ 19 | class Polygonizer { 20 | public: 21 | /** 22 | * @brief Converts TM2IN::RoomBoundary::TriangulatedSurfaceMesh to TM2IN::RoomBoundary::PolygonMesh 23 | */ 24 | virtual TM2IN::RoomBoundary::PolygonMesh* run(TM2IN::RoomBoundary::TSM* space) = 0; 25 | }; 26 | 27 | /** 28 | * Converter TM2IN::RoomBoundary::TriangulatedSurfaceMesh to TM2IN::RoomBoundary::PolygonMesh 29 | */ 30 | class TrianglePolygonizer : public Polygonizer{ 31 | public: 32 | /** 33 | * @brief Converts TM2IN::RoomBoundary::TriangulatedSurfaceMesh to TM2IN::RoomBoundary::PolygonMesh 34 | */ 35 | TM2IN::RoomBoundary::PolygonMesh* run(TM2IN::RoomBoundary::TSM* space); 36 | }; 37 | 38 | /** 39 | * Converter TM2IN::RoomBoundary::TriangulatedSurfaceMesh to TM2IN::RoomBoundary::PolygonMesh 40 | */ 41 | class DividedPolygonizer : public Polygonizer { 42 | public: 43 | /** 44 | * @brief Converts TM2IN::RoomBoundary::TriangulatedSurfaceMesh to TM2IN::RoomBoundary::PolygonMesh 45 | */ 46 | TM2IN::RoomBoundary::PolygonMesh* run(TM2IN::RoomBoundary::TSM* space); 47 | }; 48 | 49 | /** 50 | * Converter by using PCA 51 | * @todo 52 | */ 53 | class PCAPolygonizer : public Polygonizer { 54 | public: 55 | /** 56 | * @brief Converts TM2IN::RoomBoundary::TriangulatedSurfaceMesh to TM2IN::RoomBoundary::PolygonMesh 57 | */ 58 | TM2IN::RoomBoundary::PolygonMesh* run(TM2IN::RoomBoundary::TSM* space); 59 | private: 60 | void scale_up(vector &vertices, double scale); 61 | // SFCGAL::Polygon make_sf_polygon(vector vertices); 62 | }; 63 | } 64 | } 65 | 66 | 67 | #endif //TM2IN_POLYGONIZER_H 68 | -------------------------------------------------------------------------------- /algorithm/collinear.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 23. 3 | // 4 | #include "collinear.h" 5 | 6 | #include "cgal/vector_angle.h" 7 | #include "features/Vertex.h" 8 | #include "detail/cgal_config.h" 9 | 10 | namespace TM2IN { 11 | double threshold_collinear = 0.001; 12 | namespace algorithm { 13 | bool has_lower_angle_than(Vertex* origin, Vertex* v1, Vertex* v2, double degree){ 14 | Vector_3 vec1(origin->CGAL_point(),v1->CGAL_point()); 15 | Vector_3 vec2(origin->CGAL_point(),v2->CGAL_point()); 16 | assert(vec1.squared_length() > 0 && vec2.squared_length() > 0); 17 | 18 | return TM2IN::cgal::has_lower_angle_than(vec1, vec2, degree); 19 | } 20 | bool isCollinear(Vertex *start_p, Vertex *check_p, Vertex *end_p){ 21 | return (has_lower_angle_than(start_p, check_p, end_p, TM2IN::threshold_collinear) 22 | || has_lower_angle_than(end_p, check_p, start_p, TM2IN::threshold_collinear) 23 | || has_lower_angle_than(check_p, end_p, start_p, TM2IN::threshold_collinear)); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /algorithm/collinear.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 23. 3 | // 4 | 5 | #ifndef TM2IN_ALGORITHM_COLLINEAR_H 6 | #define TM2IN_ALGORITHM_COLLINEAR_H 7 | 8 | #include 9 | 10 | namespace TM2IN{ 11 | /** 12 | * Threshold value for determining collinear vectors. 13 | * @warning Default value is 0.001. 14 | */ 15 | extern double threshold_collinear; 16 | namespace algorithm{ 17 | /** 18 | * @ingroup public_api 19 | * @brief Compares angle between Vector(origin, v1) and Vector(origin, v2) and the specific angle. 20 | */ 21 | bool has_lower_angle_than(Vertex* origin, Vertex* v1, Vertex* v2, double angle); 22 | /** 23 | * @ingroup public_api 24 | * @brief Determines whether the line string (start_p, check_p, end_p) is collinear. 25 | * 26 | */ 27 | bool isCollinear(Vertex *start_p, Vertex *check_p, Vertex *end_p); 28 | } 29 | } 30 | 31 | #endif //TM2IN_COLLINEAR_H 32 | -------------------------------------------------------------------------------- /algorithm/compare.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 24. 3 | // 4 | 5 | #include 6 | 7 | #include "compare.h" 8 | #include "features/IndoorComponent.h" 9 | 10 | namespace TM2IN{ 11 | namespace algorithm{ 12 | bool greater(Vertex * a, Vertex * b) { 13 | ll multiple = pow(10, DECIMAL); 14 | int ax = (int)(a->x() * multiple); 15 | int bx = (int)(b->x() * multiple); 16 | int ay = (int)(a->y() * multiple); 17 | int by = (int)(b->y() * multiple); 18 | int az = (int)(a->z() * multiple); 19 | int bz = (int)(b->z() * multiple); 20 | 21 | if (ax < bx){ 22 | return true; 23 | } 24 | else if (ax > bx){ 25 | return false; 26 | } 27 | else{ 28 | if (ay < by) 29 | { 30 | return true; 31 | } 32 | else if (ay > by) 33 | { 34 | return false; 35 | } 36 | else{ 37 | if (az < bz) 38 | { 39 | return true; 40 | } 41 | else if (az > bz) 42 | return false; 43 | else 44 | return false; 45 | } 46 | } 47 | } 48 | 49 | bool compareArea(IndoorComponent *i, IndoorComponent *j) { 50 | return (i->getArea() > j->getArea()); 51 | } 52 | 53 | bool is_same_vertex(Vertex *a, Vertex *b) { 54 | int multiple = (int)pow(10, DECIMAL); 55 | int ax = (int)(a->x() * multiple); 56 | int bx = (int)(b->x() * multiple); 57 | int ay = (int)(a->y() * multiple); 58 | int by = (int)(b->y() * multiple); 59 | int az = (int)(a->z() * multiple); 60 | int bz = (int)(b->z() * multiple); 61 | 62 | return ax == bx && ay == by && az == bz; 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /algorithm/compare.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 24. 3 | // 4 | 5 | #ifndef TM2IN_COMPARE_H 6 | #define TM2IN_COMPARE_H 7 | 8 | #include "detail/cgal_config.h" 9 | #include "features/Vertex.h" 10 | 11 | class IndoorComponent; 12 | namespace TM2IN { 13 | namespace algorithm { 14 | /** 15 | * @ingroup public_api 16 | * @brief Compares two Vertices 17 | */ 18 | bool greater(Vertex * a, Vertex * b); 19 | /** 20 | * @ingroup public_api 21 | * @brief Compares two Indoor Component by calculating area. 22 | */ 23 | bool compareArea(IndoorComponent* i, IndoorComponent* j); 24 | 25 | bool is_same_vertex(Vertex * a, Vertex * b); 26 | } 27 | } 28 | 29 | #endif //TM2IN_COMPARE_H 30 | -------------------------------------------------------------------------------- /algorithm/mbb.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 24. 3 | // 4 | 5 | #include "features/Wall/Surface.h" 6 | #include "mbb.h" 7 | 8 | using namespace std; 9 | 10 | namespace TM2IN{ 11 | namespace algorithm{ 12 | CGAL::Bbox_3 getMBB(std::vector &surfacesList){ 13 | vector> v_minmax; 14 | v_minmax.assign(2, vector()); 15 | 16 | for (int i = 0 ; i < 3 ; i++) 17 | { 18 | v_minmax[1].push_back(-100000.0000); 19 | v_minmax[0].push_back(100000.0000); 20 | } 21 | 22 | for (ull i = 0 ; i < surfacesList.size() ; i++){ 23 | Wall::Surface* cp = surfacesList[i]; 24 | cp->updateMBB(); 25 | for (int j = 0 ; j < 3 ; j++){ 26 | v_minmax[1][j] = max(v_minmax[1][j], bbox3_max_with_index(cp->getMBB(), j)); 27 | v_minmax[0][j] = min(v_minmax[0][j], bbox3_min_with_index(cp->getMBB(), j)); 28 | } 29 | } 30 | 31 | CGAL::Bbox_3 bbox_3(v_minmax[0][0],v_minmax[0][1], v_minmax[0][2], v_minmax[1][0], v_minmax[1][1], v_minmax[1][2]); 32 | return bbox_3; 33 | } 34 | 35 | double bbox3_max_with_index(CGAL::Bbox_3 bbox3, int index) { 36 | if (index == 0) 37 | return bbox3.xmax(); 38 | else if (index == 1) 39 | return bbox3.ymax(); 40 | else if (index == 2) 41 | return bbox3.zmax(); 42 | throw std::runtime_error("MinimumBoundingBox::max(int index) : out of range"); 43 | } 44 | 45 | double bbox3_min_with_index(CGAL::Bbox_3 bbox3, int index) { 46 | if (index == 0) 47 | return bbox3.xmin(); 48 | else if (index == 1) 49 | return bbox3.ymin(); 50 | else if (index == 2) 51 | return bbox3.zmin(); 52 | throw std::runtime_error("bbox3_min_with_index(int index) : out of range"); 53 | } 54 | 55 | 56 | } 57 | } -------------------------------------------------------------------------------- /algorithm/mbb.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 24. 3 | // 4 | 5 | #ifndef TM2IN_MBB_H 6 | #define TM2IN_MBB_H 7 | 8 | #include "detail/cgal_config.h" 9 | #include "features/IndoorComponent.h" 10 | 11 | namespace TM2IN{ 12 | namespace algorithm{ 13 | /** 14 | * @ingroup public_api 15 | * @brief Gets CGAL::Bbox_3 for Surface list. 16 | */ 17 | CGAL::Bbox_3 getMBB(std::vector &surfacesList); 18 | 19 | double bbox3_max_with_index(CGAL::Bbox_3 bbox3, int index); 20 | double bbox3_min_with_index(CGAL::Bbox_3 bbox3, int index); 21 | } 22 | } 23 | 24 | #endif //TM2IN_MBB_H 25 | -------------------------------------------------------------------------------- /algorithm/merge_surfaces.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 19. 3 | // 4 | 5 | #include "algorithm/merge_surfaces.h" 6 | 7 | #include 8 | #include 9 | #include "detail/algorithm/merge_surfaces.h" 10 | #include "detail/algorithm/simplify_share_edges.h" 11 | #include "features/Wall/TriangulatedSurface.h" 12 | #include "features/RoomBoundary/TriangulatedSurfaceMesh.h" 13 | 14 | using namespace TM2IN::detail::algorithm; 15 | using namespace TM2IN::RoomBoundary; 16 | 17 | namespace TM2IN{ 18 | namespace algorithm{ 19 | bool mergeSurfaces(TriangulatedSurfaceMesh *tsm, double thres1, double thres2) { 20 | vector new_poly_list; 21 | SurfaceMerger sm(thres1, thres2); 22 | bool hasMerged = sm.mergeSurfaces(tsm->surface_list(), new_poly_list); 23 | tsm->setSurfacesList(new_poly_list); 24 | return hasMerged; 25 | } 26 | 27 | int cleanMergedSurfaces(TriangulatedSurfaceMesh *tsm) { 28 | bool hasSimplified = false; 29 | cout << "\n------------clean_merging_result------------\n" << endl; 30 | sort(tsm->surfaces.begin(), tsm->surfaces.end(), Surface::compareLength); 31 | ull sizeOfSurfaces = tsm->surfaces.size(); 32 | 33 | for (ull i = 0 ; i < sizeOfSurfaces; i++) 34 | assert((int) tsm->surfaces[i]->getVerticesSize() >= 3); 35 | 36 | for (ull i = 0 ; i < sizeOfSurfaces - 1; i++){ 37 | Wall::TriangulatedSurface *&surfaceI = tsm->surfaces[i]; 38 | if (!surfaceI->easy_validation()) continue; 39 | printProcess(i, sizeOfSurfaces, ""); 40 | for (ull j = i + 1; j < sizeOfSurfaces ; j++){ 41 | Wall::TriangulatedSurface *&surfaceJ = tsm->surfaces[j]; 42 | if (!surfaceI->easy_validation()) break; 43 | if (!surfaceJ->easy_validation()) continue; 44 | if (!TM2IN::detail::cgal::has_bbox_intersect(surfaceI, surfaceJ)) continue; 45 | while (simplify_share_edges(tsm->surfaces[i], tsm->surfaces[j]) == 0){ 46 | hasSimplified = true; 47 | if (!surfaceI->easy_validation() || !surfaceJ->easy_validation()) break; 48 | } 49 | } 50 | } 51 | sizeOfSurfaces = tsm->surfaces.size(); 52 | 53 | bool hasRemoved = false; 54 | for (int i = sizeOfSurfaces - 1; i >= 0 ; i--){ 55 | if (tsm->surfaces[i]->strict_validation()){ 56 | } 57 | else{ 58 | hasRemoved = true; 59 | cerr << "remove" << endl; 60 | TM2IN::detail::HalfEdgeString::setParent(tsm->surfaces[i]->getExteriorBoundary(), NULL); 61 | delete tsm->surfaces[i]; 62 | tsm->surfaces.erase(tsm->surfaces.begin() + i); 63 | } 64 | } 65 | 66 | if (hasRemoved) 67 | hasSimplified = (cleanMergedSurfaces(tsm) || hasSimplified); 68 | 69 | return hasSimplified; 70 | } 71 | 72 | bool mergeSurfaces(std::vector& surfaceList, double thres1, double thres2, vector& newSurfaceList) { 73 | SurfaceMerger sm(thres1, thres2); 74 | bool hasMerged = sm.mergeSurfaces(surfaceList, newSurfaceList); 75 | return hasMerged; 76 | } 77 | 78 | bool mergeTriangles(vector &triangleList, double thres1, double thres2, 79 | vector &newSurfaceList) { 80 | vector surfaceList; 81 | for (Wall::Triangle* tri : triangleList) 82 | surfaceList.push_back(new Wall::TriangulatedSurface(tri)); 83 | SurfaceMerger sm(thres1, thres2); 84 | bool hasMerged = sm.mergeSurfaces(surfaceList, newSurfaceList); 85 | for(Wall::TriangulatedSurface* sf : surfaceList) 86 | delete sf; 87 | return hasMerged; 88 | } 89 | 90 | 91 | } 92 | } -------------------------------------------------------------------------------- /algorithm/merge_surfaces.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 19. 3 | // 4 | 5 | #ifndef TM2IN_MERGE_SURFACES_H 6 | #define TM2IN_MERGE_SURFACES_H 7 | 8 | #include "features/IndoorComponent.h" 9 | 10 | using namespace std; 11 | 12 | namespace TM2IN{ 13 | namespace algorithm{ 14 | /** 15 | * @ingroup public_api 16 | * @brief Merges TM2IN::RoomBoundary::TriangulatedSurfaceMesh to larger one. 17 | */ 18 | bool mergeSurfaces(TM2IN::RoomBoundary::TriangulatedSurfaceMesh* tsm, double thres1, double thres2); 19 | /** 20 | * @ingroup public_api 21 | * @brief Merges the list of Surface. Result will be stored in 4th parameter. 22 | */ 23 | bool mergeSurfaces(vector& surfaceList, double thres1, double thres2, vector& newSurfaceList); 24 | /** 25 | * @ingroup public_api 26 | * @brief Merges the list of Triangle. Result will be stored in 4th parameter. 27 | */ 28 | bool mergeTriangles(vector& triangleList, double thres1, double thres2, vector& newSurfaceList); 29 | /** 30 | * @ingroup public_api 31 | * @brief Cleans TM2IN::RoomBoundary::TriangulatedSurfaceMesh after merging. 32 | */ 33 | int cleanMergedSurfaces(TM2IN::RoomBoundary::TriangulatedSurfaceMesh* tsm); 34 | } 35 | } 36 | #endif //TM2IN_MERGE_SURFACES_H 37 | -------------------------------------------------------------------------------- /algorithm/triangulation.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 20. 3 | // 4 | 5 | #include "triangulation.h" 6 | 7 | #include "features/Wall/Surface.h" 8 | #include "features/Wall/Triangle.h" 9 | #include "detail/algorithm/triangulate_surface.h" 10 | 11 | using namespace std; 12 | using namespace TM2IN; 13 | 14 | namespace TM2IN { 15 | namespace algorithm { 16 | int triangulate(TM2IN::Wall::Surface *pSurface, std::vector& result) { 17 | result.clear(); 18 | 19 | std::vector vertexList = pSurface->getVerticesList(); 20 | pSurface->updateNormal(); 21 | 22 | if (vertexList.size() == 3) { 23 | TM2IN::Wall::Triangle* newTriangle = new TM2IN::Wall::Triangle(vertexList); 24 | newTriangle->geom_id = pSurface->geom_id + "_0"; 25 | result.push_back(newTriangle); 26 | return 0; 27 | } 28 | else { 29 | int return_value = TM2IN::detail::algorithm::triangulate_surface(pSurface, result); 30 | Vector_3 vt_normal(0,0,0); 31 | for (Wall::Triangle* tri : result){ 32 | vt_normal = vt_normal + tri->normal; 33 | } 34 | pSurface->normal = vt_normal; 35 | return return_value; 36 | } 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /algorithm/triangulation.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 20. 3 | // 4 | 5 | #ifndef TM2IN_TRIANGULATION_H 6 | #define TM2IN_TRIANGULATION_H 7 | 8 | #include "features/IndoorComponent.h" 9 | #include "detail/cgal_config.h" 10 | #include "detail/cgal/plane.h" 11 | #include "detail/cgal/polygon.h" 12 | 13 | namespace TM2IN { 14 | namespace algorithm { 15 | /** 16 | * @brief Triangulate one TM2IN::Surface to multiple TM2IN::Triangle objects. 17 | * @ingroup public_api 18 | */ 19 | int triangulate(TM2IN::Wall::Surface *pSurface, std::vector& result); 20 | } 21 | } 22 | 23 | #endif //TM2IN_TRIANGULATION_H 24 | -------------------------------------------------------------------------------- /cgal/polyhedron.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 1. 17. 3 | // 4 | 5 | #include "polyhedron.h" 6 | #include "features/Wall/Surface.h" 7 | #include "features/Wall/Triangle.h" 8 | #include "features/Vertex.h" 9 | 10 | #include 11 | 12 | typedef CGAL::Polyhedron_3 Polyhedron; 13 | 14 | typedef Polyhedron::Halfedge_handle Halfedge_handle; 15 | typedef Polyhedron::Facet_handle Facet_handle; 16 | typedef Polyhedron::Vertex_handle Vertex_handle; 17 | typedef Polyhedron::HalfedgeDS HalfedgeDS; 18 | 19 | typedef Polyhedron::Facet_iterator Facet_iterator; 20 | typedef Polyhedron::Vertex_iterator Vertex_iterator; 21 | 22 | typedef Polyhedron::Halfedge_around_facet_circulator Halfedge_facet_circulator; 23 | 24 | namespace TM2IN { 25 | namespace unused { 26 | // A modifier creating a triangle with the incremental builder. 27 | template 28 | class polyhedron_builder : public CGAL::Modifier_base { 29 | public: 30 | vector &coords; 31 | vector &surfaces; 32 | 33 | polyhedron_builder(vector &_vertices, vector &_surfaces) : coords(_vertices), 34 | surfaces(_surfaces) {} 35 | 36 | void operator()(HDS &hds) { 37 | typedef typename HDS::Vertex HDS_Vertex; 38 | typedef typename HDS_Vertex::Point Point; 39 | 40 | // create a cgal incremental builder 41 | CGAL::Polyhedron_incremental_builder_3 B(hds, true); 42 | B.begin_surface(coords.size(), surfaces.size()); 43 | 44 | cout << coords.size() << " , " << surfaces.size() << endl; 45 | 46 | map vertex_index; 47 | // add the polyhedron vertices 48 | for (int i = 0; i < (int) coords.size(); i++) { 49 | B.add_vertex(Point(coords[i]->coords[0], coords[i]->coords[1], coords[i]->coords[2])); 50 | Vertex * pVertex = coords[i]; 51 | vertex_index[pVertex] = i; 52 | } 53 | 54 | // add the polyhedron triangles 55 | for (int i = 0; i < (int) surfaces.size(); i++) { 56 | B.begin_facet(); 57 | vector vt_list = surfaces[i]->getVerticesList(); 58 | for (auto vt : vt_list) { 59 | int index = vertex_index[vt]; 60 | B.add_vertex_to_facet(index); 61 | } 62 | 63 | B.end_facet(); 64 | } 65 | 66 | // finish up the surface 67 | B.end_surface(); 68 | } 69 | }; 70 | 71 | vector fillHole(vector &vertices, vector &triangles) { 72 | Polyhedron poly; 73 | polyhedron_builder polybuilder(vertices, triangles); 74 | poly.delegate(polybuilder); 75 | // Incrementally fill the holes 76 | unsigned int nb_holes = 0; 77 | BOOST_FOREACH(Halfedge_handle h, halfedges(poly)) { 78 | if (h->is_border()) { 79 | std::vector patch_facets; 80 | std::vector patch_vertices; 81 | bool success = CGAL::cpp11::get<0>( 82 | CGAL::Polygon_mesh_processing::triangulate_refine_and_fair_hole( 83 | poly, 84 | h, 85 | std::back_inserter(patch_facets), 86 | std::back_inserter(patch_vertices), 87 | CGAL::Polygon_mesh_processing::parameters::vertex_point_map( 88 | get(CGAL::vertex_point, poly)). 89 | geom_traits(Kernel()))); 90 | std::cout << " Number of facets in constructed patch: " << patch_facets.size() 91 | << std::endl; 92 | std::cout << " Number of vertices in constructed patch: " << patch_vertices.size() 93 | << std::endl; 94 | std::cout << " Fairing : " << (success ? "succeeded" : "failed") << std::endl; 95 | ++nb_holes; 96 | } 97 | } 98 | std::cout << std::endl; 99 | std::cout << nb_holes << " holes have been filled" << std::endl; 100 | 101 | vector new_triangles; 102 | vector newVertices; 103 | for (Vertex_iterator i = poly.vertices_begin(); i != poly.vertices_end(); ++i) { 104 | Vertex * vt = new Vertex(i->point().x(), i->point().y(), i->point().z()); 105 | newVertices.push_back(vt); 106 | } 107 | 108 | for (Facet_iterator i = poly.facets_begin(); i != poly.facets_end(); i++) { 109 | Halfedge_facet_circulator j = i->facet_begin(); 110 | 111 | vector oneSurfaceCoords; 112 | CGAL_assertion(CGAL::circulator_size(j) >= 3); 113 | do { 114 | ull vtIndex = std::distance(poly.vertices_begin(), j->vertex()); 115 | oneSurfaceCoords.push_back(newVertices[vtIndex]); 116 | } while (++j != i->facet_begin()); 117 | Wall::Triangle * triangle = new Wall::Triangle(oneSurfaceCoords); 118 | new_triangles.push_back(triangle); 119 | } 120 | 121 | triangles.clear(); 122 | triangles = new_triangles; 123 | return newVertices; 124 | } 125 | } 126 | } -------------------------------------------------------------------------------- /cgal/polyhedron.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 1. 17. 3 | // 4 | 5 | #ifndef POLYHEDRON_H 6 | #define POLYHEDRON_H 7 | 8 | #include 9 | #include 10 | #include "features/IndoorComponent.h" 11 | 12 | using namespace std; 13 | using namespace TM2IN; 14 | 15 | namespace TM2IN{ 16 | namespace unused{ 17 | /** 18 | * @brief Fills hole in surfaces 19 | * @ingroup unused 20 | */ 21 | vector fillHole(vector& vertices, vector& triangles); 22 | } 23 | }; 24 | 25 | 26 | #endif //POLYHEDRON_H 27 | -------------------------------------------------------------------------------- /cgal/triangle.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 24. 3 | // 4 | 5 | #include "triangle.h" 6 | 7 | #define SCALE 1000 8 | 9 | namespace TM2IN { 10 | namespace cgal { 11 | double triangle_area(Vertex *va, Vertex *vb, Vertex *vc){ 12 | Point_3 p3a(va->x(),va->y(),va->z()); 13 | Point_3 p3b(vb->x(),vb->y(),vb->z()); 14 | Point_3 p3c(vc->x(),vc->y(),vc->z()); 15 | return triangle_area(p3a, p3b, p3c); 16 | } 17 | 18 | double triangle_area(Point_3 &p1, Point_3 &p2, Point_3 &p3){ 19 | Triangle_3 tri(p1,p2,p3); 20 | return tri.squared_area(); 21 | } 22 | 23 | Vector_3 triangle_normal(TM2IN::Vertex *va, TM2IN::Vertex *vb, TM2IN::Vertex *vc) { 24 | Point_3 p3a(va->x(),va->y(),va->z()); 25 | Point_3 p3b(vb->x(),vb->y(),vb->z()); 26 | Point_3 p3c(vc->x(),vc->y(),vc->z()); 27 | 28 | Vector_3 vab(p3a, p3b); 29 | Vector_3 vac(p3a, p3c); 30 | 31 | return CGAL::cross_product(vab, vac); 32 | } 33 | 34 | } 35 | } -------------------------------------------------------------------------------- /cgal/triangle.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 24. 3 | // 4 | #ifndef TM2IN_TRIANGLE_H 5 | #define TM2IN_TRIANGLE_H 6 | 7 | #include "detail/cgal_config.h" 8 | #include "features/Vertex.h" 9 | 10 | namespace TM2IN { 11 | namespace cgal{ 12 | /** 13 | * @brief Returns normal vector of triangle 14 | * @ingroup public_api 15 | */ 16 | Vector_3 triangle_normal(TM2IN::Vertex *va, TM2IN::Vertex *vb, TM2IN::Vertex *vc); 17 | /** 18 | * @brief Returns the area of triangle 19 | * @ingroup public_api 20 | */ 21 | double triangle_area(Vertex *va, Vertex *vb, Vertex *vc); 22 | /** 23 | * @brief Returns the area of triangle 24 | * @ingroup public_api 25 | */ 26 | double triangle_area(Point_3 &p1, Point_3 &p2, Point_3 &p3); 27 | } 28 | } 29 | 30 | #endif //TM2IN_TRIANGLE_H 31 | -------------------------------------------------------------------------------- /cgal/vector_angle.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 23. 3 | // 4 | #define PI 3.14159265 5 | 6 | #include 7 | #include "detail/cgal/vector_3.h" 8 | #include "vector_angle.h" 9 | 10 | 11 | 12 | namespace TM2IN { 13 | namespace cgal { 14 | 15 | double getAngle(Vector_3 &nv1, Vector_3 &nv2) { 16 | if (!Options::getInstance()->do_validation && (nv1.squared_length() == 0 || nv2.squared_length() == 0)){ 17 | return 0; 18 | } 19 | double cos = TM2IN::detail::cgal::getCosineValue(nv1, nv2); 20 | double angle = acos(cos) * 180.0 / PI; 21 | 22 | assert(angle == angle); //check NAN 23 | return angle; 24 | } 25 | 26 | bool has_lower_angle_than(Vector_3 &nv1, Vector_3 &nv2, double degree){ 27 | double angle = getAngle(nv1, nv2); 28 | assert(angle >= 0); 29 | return (angle <= degree); 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /cgal/vector_angle.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 23. 3 | // 4 | 5 | #ifndef TM2IN_CGAL_VECTOR_H 6 | #define TM2IN_CGAL_VECTOR_H 7 | 8 | #include "detail/cgal_config.h" 9 | 10 | namespace TM2IN{ 11 | namespace cgal{ 12 | /** 13 | * @brief Returns the angle between v1 and v2. 14 | * @ingroup public_api 15 | */ 16 | double getAngle(Vector_3& v1, Vector_3& v2); 17 | /** 18 | * @brief Checks the angle between v1 and v2 is lower than the angle 19 | * @ingroup public_api 20 | */ 21 | bool has_lower_angle_than(Vector_3 &nv1, Vector_3 &nv2, double angle); 22 | } 23 | } 24 | 25 | 26 | 27 | #endif //TM2IN_CGAL_VECTOR_H 28 | -------------------------------------------------------------------------------- /compute/unused.h: -------------------------------------------------------------------------------- 1 | #ifndef TM2IN_UNUSED_H 2 | #define TM2IN_UNUSED_H 3 | 4 | #include "features/Wall/Surface.h" 5 | #include "detail/cgal_config.h" 6 | 7 | using namespace TM2IN::Wall; 8 | 9 | namespace TM2IN { 10 | namespace unused { 11 | /** 12 | * @brief Removes straight vertices in Surface 13 | * @ingroup unused 14 | */ 15 | void removeStraight(Surface*& pSurface); 16 | /** 17 | * @brief Converts Kernel::Segment_2 list from Surface 18 | * @ingroup unused 19 | */ 20 | std::vector makeSegment2List(Surface *&pSurface, Plane_3 plane3); 21 | /** 22 | * @brief Resolves self-intersection in Surface 23 | * @ingroup unused 24 | */ 25 | std::vector resolveSelfIntersection(Surface *&pSurface); 26 | /** 27 | * @brief Resolves self-intersection in Surface 28 | * @ingroup unused 29 | */ 30 | void resolveEasySelfIntersection(Surface *&pSurface); 31 | /** 32 | * @brief Resolves self-intersection in Surface 33 | * @ingroup unused 34 | */ 35 | int makeNewIntersectionVertex(Surface *&pSurface); 36 | } 37 | } 38 | 39 | #endif //TM2IN_UNUSED_H 40 | -------------------------------------------------------------------------------- /config.h: -------------------------------------------------------------------------------- 1 | #ifndef PREDEFINE_H_INCLUDED 2 | #define PREDEFINE_H_INCLUDED 3 | 4 | 5 | #define PI 3.14159265 6 | #define AREA_CONST 100 7 | #define DECIMAL 6 8 | 9 | #include 10 | #include 11 | 12 | #endif // PREDEFINE_H_INCLUDED 13 | -------------------------------------------------------------------------------- /converter/Converter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "config.h" 8 | #include "features/HalfEdge.h" 9 | #include "features/Wall/Triangle.h" 10 | #include "features/Room.h" 11 | #include "features/RoomBoundary/TriangleMesh.h" 12 | #include "features/RoomBoundary/PolygonMesh.h" 13 | 14 | #include "Converter.h" 15 | 16 | using namespace TM2IN; 17 | 18 | Converter::Converter(){} 19 | 20 | int Converter::start() { 21 | importData(); // import mesh data 22 | if (Options::getInstance()->do_validation) 23 | validate_tm(); 24 | /* 25 | if (options.generator) generation_writer = new GenerationWriter(options.output_dir); // generation writer 26 | */ 27 | return 0; 28 | } 29 | 30 | int Converter::run() { 31 | mergeSurfaces(); 32 | if (Options::getInstance()->has_no_merge) 33 | return 0; 34 | 35 | if (Options::getInstance()->do_validation) 36 | validate_tsm(); 37 | 38 | if (Options::getInstance()->do_classification) 39 | classify_sf_type(); 40 | 41 | if (Options::getInstance()->polygonizer_mode > 0) // 1 or 2 or 3 42 | polygonize(); 43 | 44 | return 0; 45 | } 46 | 47 | int Converter::finish() { 48 | cout << "\n\n"; 49 | this->tag_pm_ID(); 50 | this->exportRoomBoundary(); 51 | 52 | return 0; 53 | } 54 | 55 | int Converter::exportRoomBoundary() { 56 | //JSON 57 | if (Options::getInstance()->polygonizer_mode > 0) 58 | TM2IN::io::exportRoomBoundaryJSON(Options::getInstance()->output_dir + "surfaces.json", this->rooms, 0); 59 | else 60 | TM2IN::io::exportRoomBoundaryJSON(Options::getInstance()->output_dir + "surfaces.json", this->rooms, 3); 61 | 62 | if (Options::getInstance()->polygonizer_mode > 0 && Options::getInstance()->output_indoor_gml){ 63 | TM2IN::io::exportIndoorGML_infactory((Options::getInstance()->output_dir + "tm2in.gml").c_str(), this->rooms); 64 | } 65 | 66 | if (Options::getInstance()->output_3ds || Options::getInstance()->output_tvr){ 67 | convert_pm_to_tm(); 68 | } 69 | 70 | //TVR 71 | if (Options::getInstance()->output_tvr){ 72 | 73 | } 74 | 75 | //3DS 76 | if (Options::getInstance()->output_3ds){ 77 | TM2IN::io::export3DS((Options::getInstance()->output_dir + Options::getInstance()->file_name + ".3DS").c_str(), this->rooms); 78 | } 79 | return 0; 80 | } 81 | 82 | int Converter::convert_pm_to_tm(){ 83 | for (int room_id = 0 ; room_id < this->rooms.size() ; room_id++){ 84 | auto room = this->rooms[room_id]; 85 | 86 | RoomBoundary::TriangleMesh* tm = room->getPm_boundary()->to_triangle_mesh(); 87 | room->setTm_boundary(tm); 88 | } 89 | return 0; 90 | } 91 | 92 | 93 | void Converter::tag_pm_ID() { 94 | for (ull it = 0 ; it < this->rooms.size() ; it++) { 95 | auto room = this->rooms[it]; 96 | if (room->getPm_boundary() != NULL){ 97 | room->getPm_boundary()->tag_ID(room->geom_id); 98 | } 99 | 100 | } 101 | } 102 | 103 | void Converter::validate_tm() { 104 | 105 | } 106 | -------------------------------------------------------------------------------- /converter/Converter.h: -------------------------------------------------------------------------------- 1 | #ifndef MANAGER_H 2 | #define MANAGER_H 3 | 4 | #include "Options.h" 5 | #include "util.h" 6 | #include "algorithm/Polygonizer.h" 7 | #include "features/IndoorComponent.h" 8 | 9 | using namespace TM2IN; 10 | 11 | class Converter 12 | { 13 | protected: 14 | public: 15 | vector rooms; 16 | 17 | Converter(); 18 | virtual ~Converter(){}; 19 | 20 | /** 21 | * Ready to run projects. Triangle Mesh data -> TM2IN::TriangleMesh Class Objects 22 | */ 23 | int start(); 24 | 25 | /** 26 | * Converts data. TM2IN::TriangleMesh -> TM2IN::TriangulatedSurfaceMesh 27 | */ 28 | int run(); 29 | 30 | /** 31 | * Finish and export data. TM2IN::TriangulatedSurfaceMesh -> TM2IN::PolygonMesh 32 | * @return Succeed : 0 33 | */ 34 | int finish(); 35 | private: 36 | // start 37 | int importData(); 38 | void print_input_spec(); 39 | 40 | // run 41 | int mergeSurfaces(); 42 | void make_tri_surface_mesh(Room*); 43 | int validate_tsm(); 44 | int polygonize(); 45 | TM2IN::algorithm::Polygonizer *create_polygonizer(); 46 | int classify_sf_type(); 47 | 48 | // finish 49 | void tag_pm_ID(); 50 | int convert_pm_to_tm(); 51 | int exportRoomBoundary(); 52 | 53 | void validate_tm(); 54 | }; 55 | 56 | #endif // MANAGER_H 57 | -------------------------------------------------------------------------------- /converter/run.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 19. 3 | // 4 | #include "converter/Converter.h" 5 | 6 | #include 7 | #include "io/GenerationWriter.h" 8 | #include "features/Room.h" 9 | #include "features/RoomBoundary/TriangulatedSurfaceMesh.h" 10 | 11 | 12 | int Converter::mergeSurfaces() { 13 | TM2IN::io::GenerationWriter* gw = TM2IN::io::GenerationWriter::getInstance(); 14 | clock_t begin = clock(); 15 | for (ull it = 0 ; it < this->rooms.size(); it++) 16 | { 17 | Room* room = this->rooms[it]; 18 | if (Options::getInstance()->generator) 19 | gw->start(room); 20 | make_tri_surface_mesh(room); 21 | if (Options::getInstance()->generator) 22 | gw->close(); 23 | } 24 | clock_t end = clock(); 25 | cout << "merge Surfaces time : " << double(end - begin) / CLOCKS_PER_SEC << "s" << endl; 26 | return 0; 27 | } 28 | 29 | void Converter::make_tri_surface_mesh(Room* room) { 30 | RoomBoundary::TriangleMesh *tm = room->getTm_boundary(); 31 | RoomBoundary::TriangulatedSurfaceMesh* tsm = new RoomBoundary::TriangulatedSurfaceMesh(tm); 32 | room->setTsm_boundary(tsm); 33 | 34 | ll p_size = (ull)tsm->num_of_surfaces(); 35 | double thres1 = Options::getInstance()->threshold_1; 36 | double thres2 = Options::getInstance()->threshold_2; 37 | Options::getInstance()->generation = 0; 38 | 39 | if (Options::getInstance()->has_no_merge) 40 | return; 41 | 42 | while (true){ 43 | if (Options::getInstance()->generator) 44 | TM2IN::io::GenerationWriter::getInstance()->write(tsm); 45 | assert(p_size > 0); 46 | cout << "generation " << Options::getInstance()->generation << ": " << tsm->num_of_surfaces()<< endl; 47 | cout << "degree : " << thres1 << endl; 48 | bool hasMerged = TM2IN::algorithm::mergeSurfaces(tsm, thres1, thres2); 49 | 50 | int simplifySegment = 0; 51 | if (!hasMerged){ 52 | simplifySegment = TM2IN::algorithm::cleanMergedSurfaces(tsm); // space->clean_merging_result(); 53 | if (simplifySegment == -1){ 54 | throw std::runtime_error("simplifySegment\n"); 55 | } 56 | } 57 | 58 | if (tsm->surface_easy_validation() == -1){ 59 | throw std::runtime_error("Surface is not valid\n"); 60 | } 61 | 62 | if (hasMerged || simplifySegment){ 63 | p_size = (int)tsm->num_of_surfaces(); 64 | } 65 | else{ 66 | cout << "generation " << Options::getInstance()->generation << " done..\n\n\n"<< endl; 67 | break; 68 | } 69 | if (thres1 < 40) thres1 += 2.0; 70 | 71 | Options::getInstance()->generation = Options::getInstance()->generation + 1; 72 | // tsm->update_surfaces_normal(); 73 | } 74 | 75 | } 76 | 77 | int Converter::validate_tsm() { 78 | for (ull it = 0 ; it < this->rooms.size() ; it++) { 79 | auto room = this->rooms[it]; 80 | RoomBoundary::TriangulatedSurfaceMesh* tsm = room->getTsm_boundary(); 81 | if (!tsm->isClosed()){ 82 | throw std::runtime_error("space " + room->geom_id + " is not closed"); 83 | } 84 | if (tsm->surface_strict_validation()){ 85 | throw std::runtime_error("space " + room->geom_id + "'s surfaces are not valid"); 86 | } 87 | } 88 | return 0; 89 | } 90 | 91 | int Converter::classify_sf_type(){ 92 | cout << "classify_sf_type" << endl; 93 | for (ull it = 0 ; it < this->rooms.size() ; it++) { 94 | auto room = this->rooms[it]; 95 | RoomBoundary::TriangulatedSurfaceMesh* tsm = room->getTsm_boundary(); 96 | tsm->classify_sf_type(); 97 | } 98 | return 0; 99 | } 100 | 101 | int Converter::polygonize() { 102 | TM2IN::algorithm::Polygonizer* polygonizer = create_polygonizer(); 103 | for (ull it = 0 ; it < this->rooms.size() ; it++) { 104 | auto room = this->rooms[it]; 105 | RoomBoundary::PolygonMesh* pm = polygonizer->run(room->getTsm_boundary()); 106 | room->setPm_boundary(pm); 107 | } 108 | return 0; 109 | } 110 | 111 | 112 | TM2IN::algorithm::Polygonizer *Converter::create_polygonizer() { 113 | switch(Options::getInstance()->polygonizer_mode){ 114 | case 1: 115 | return new TM2IN::algorithm::PCAPolygonizer(); 116 | case 2: 117 | return new TM2IN::algorithm::TrianglePolygonizer(); 118 | case 3: 119 | return new TM2IN::algorithm::DividedPolygonizer(); 120 | default: 121 | break; 122 | } 123 | throw std::runtime_error("options.polygonizer_mode has wrong value"); 124 | } 125 | 126 | -------------------------------------------------------------------------------- /converter/start.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 18. 3 | // 4 | 5 | 6 | #include 7 | #include "converter/Converter.h" 8 | 9 | #include "io/tvr.h" 10 | #include "io/xml.h" 11 | #include "io/max3ds.h" 12 | #include "features/Wall/Triangle.h" 13 | #include "features/Room.h" 14 | #include "features/RoomBoundary/TriangleMesh.h" 15 | 16 | int Converter::importData() { 17 | clock_t begin = clock(); 18 | switch(Options::getInstance()->input_type){ 19 | case 1: 20 | this->rooms = TM2IN::io::importTVR((Options::getInstance()->input_dir + Options::getInstance()->input_file).c_str()); 21 | break; 22 | case 2: 23 | this->rooms = TM2IN::io::import3DS((Options::getInstance()->input_dir + Options::getInstance()->input_file).c_str()); 24 | break; 25 | case 3: 26 | this->rooms = TM2IN::io::importDAE((Options::getInstance()->input_dir + Options::getInstance()->input_file).c_str()); 27 | break; 28 | default: 29 | throw std::runtime_error("\n\nImport Mesh has some problem\n\n"); 30 | } 31 | if (this->rooms.size() == 0){ 32 | throw std::runtime_error("\n\nImport Mesh has some problem\n\n"); 33 | } 34 | clock_t end = clock(); 35 | cout << "Importing time : " << double(end - begin) / CLOCKS_PER_SEC << "s" << endl; 36 | print_input_spec(); 37 | 38 | return 0; 39 | } 40 | 41 | 42 | /** 43 | * Print Data speciation 44 | */ 45 | void Converter::print_input_spec() { 46 | double area_sum = 0.0; 47 | vector surfaces; 48 | for (ull it = 0 ; it < this->rooms.size() ; it++){ 49 | for (Wall::Triangle* triangle : this->rooms[it]->getTm_boundary()->getTriangleList()){ 50 | surfaces.push_back((Wall::Surface*)triangle); 51 | area_sum += triangle->getArea(); 52 | } 53 | } 54 | 55 | int trianglesCount = surfaces.size(); 56 | CGAL::Bbox_3 mbb; 57 | mbb = TM2IN::algorithm::getMBB(surfaces); 58 | 59 | cout << "\n\nTriangles : " << trianglesCount << endl; 60 | cout << "Bbox : " << mbb << endl; 61 | cout << "Area : " << area_sum / (double)trianglesCount << endl; 62 | cout << "\n\n" << endl; 63 | } 64 | -------------------------------------------------------------------------------- /detail/algorithm/merge_surfaces.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 19. 3 | // 4 | 5 | #ifndef TM2IN_DETAIL_MERGE_SURFACES_H 6 | #define TM2IN_DETAIL_MERGE_SURFACES_H 7 | 8 | #include "features/IndoorComponent.h" 9 | 10 | using namespace std; 11 | using namespace TM2IN::Wall; 12 | 13 | namespace TM2IN{ 14 | namespace detail{ 15 | namespace algorithm{ 16 | /** 17 | * @ingroup imp_details 18 | */ 19 | class SurfaceMerger{ 20 | public: 21 | SurfaceMerger(double t1, double t2); 22 | bool mergeSurfaces(vector surfaceList, vector& result); 23 | private: 24 | double thres1; 25 | double thres2; 26 | 27 | int merge(Wall::TriangulatedSurface *origin, Wall::TriangulatedSurface *piece); 28 | bool check_merge_condition(Vector_3 &big, Vector_3 &small); 29 | bool is_coplanar(Vector_3 &big, Vector_3 &small); 30 | }; 31 | /** 32 | * @ingroup imp_details 33 | */ 34 | bool merging_invalid_test(vector new_edges, Vector_3 newNormal); 35 | } 36 | } 37 | } 38 | 39 | #endif //TM2IN_DETAIL_MERGE_SURFACES_H 40 | -------------------------------------------------------------------------------- /detail/algorithm/self_intersect.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 23. 3 | // 4 | 5 | #include "detail/cgal/type_conversion.h" 6 | #include "self_intersect.h" 7 | 8 | namespace TM2IN { 9 | namespace detail { 10 | namespace algorithm { 11 | bool has_self_intersection(vector edges) { 12 | vector segmentList; 13 | for (int i = 0 ; i < edges.size() ; i++){ 14 | segmentList.push_back(TM2IN::detail::cgal::to_CGAL_Segment_3(edges[i])); 15 | } 16 | for (int i = 0 ; i < segmentList.size() - 2; i++) { 17 | for (int j = i + 2; j < segmentList.size(); j++) { 18 | if (i == 0 && j == segmentList.size() - 1) continue; 19 | if (CGAL::do_intersect(segmentList[i], segmentList[j])){ 20 | segmentList.clear(); 21 | return true; 22 | } 23 | } 24 | } 25 | segmentList.clear(); 26 | return false; 27 | } 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /detail/algorithm/self_intersect.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 23. 3 | // 4 | 5 | #ifndef TM2IN_SELF_INTERSECT_H 6 | #define TM2IN_SELF_INTERSECT_H 7 | #include 8 | 9 | #include "features/HalfEdge.h" 10 | 11 | using namespace std; 12 | 13 | namespace TM2IN { 14 | namespace detail { 15 | namespace algorithm { 16 | /** 17 | * @ingroup imp_details 18 | */ 19 | bool has_self_intersection(vector edges); 20 | } 21 | } 22 | } 23 | 24 | #endif //TM2IN_SELF_INTERSECT_H 25 | -------------------------------------------------------------------------------- /detail/algorithm/simplify_share_edges.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 20. 3 | // 4 | 5 | #include 6 | #include 7 | #include "simplify_share_edges.h" 8 | #include "surface_neighbor.h" 9 | #include "features/HalfEdge.h" 10 | #include "features/Wall/TriangulatedSurface.h" 11 | 12 | namespace TM2IN { 13 | namespace detail { 14 | namespace algorithm { 15 | /** 16 | * Simplification for share edges after merging 17 | * 18 | * @todo re-factoring 19 | * @return 0 : succeed for simplification, 1 : failure 20 | */ 21 | int simplify_share_edges(Wall::TriangulatedSurface *origin, Wall::TriangulatedSurface *piece) { 22 | ll piece_middle = -1, origin_middle = -1; 23 | ll piece_size = piece->getVerticesSize(); 24 | ll origin_size = origin->getVerticesSize(); 25 | 26 | vector < Vertex * > piece_vertex_list = piece->getVerticesList(); 27 | vector < Vertex * > origin_vertex_list = origin->getVerticesList(); 28 | 29 | for (ll i = 0; i < piece_size; i++) { 30 | for (ll j = origin_size - 1; j >= 0; j--) { 31 | if (piece_vertex_list[i] == origin_vertex_list[j]) { 32 | ll next_i = i + 1 == piece_size ? 0 : i + 1; 33 | ll next_j = j - 1 == -1 ? origin_size - 1 : j - 1; 34 | 35 | ll pre_i = i - 1 == -1 ? piece_size - 1 : i - 1; 36 | ll pre_j = j + 1 == origin_size ? 0 : j + 1; 37 | 38 | if (piece_vertex_list[next_i] == origin_vertex_list[next_j] 39 | && piece_vertex_list[pre_i] == origin_vertex_list[pre_j]) { 40 | piece_middle = i; 41 | origin_middle = j; 42 | break; 43 | } 44 | } 45 | } 46 | if (piece_middle != -1) break; 47 | } 48 | 49 | if (piece_middle == -1) return 1; 50 | 51 | ll lastVertex_piece = -1, lastVertex_origin = -1; 52 | ll firstVertex_piece = -1, firstVertex_origin = -1; 53 | if (findStartAndEnd(piece_vertex_list, origin_vertex_list, piece_middle, origin_middle, 54 | firstVertex_piece, lastVertex_piece, firstVertex_origin, lastVertex_origin)) 55 | return 1; 56 | 57 | assert(origin->getSegmentsNumber(firstVertex_origin, lastVertex_origin) > 1); 58 | assert(piece->getSegmentsNumber(firstVertex_piece, lastVertex_piece) > 1); 59 | assert(piece->vertex(firstVertex_piece) == origin->vertex(lastVertex_origin)); 60 | assert(piece->vertex(lastVertex_piece) == origin->vertex(firstVertex_origin)); 61 | 62 | HalfEdge *newEdge_piece = new HalfEdge(piece->vertex(firstVertex_piece), 63 | piece->vertex(lastVertex_piece), piece); 64 | HalfEdge *newEdge_origin = new HalfEdge(origin->vertex(firstVertex_origin), 65 | origin->vertex(lastVertex_origin), origin); 66 | newEdge_origin->setOppositeEdge(newEdge_piece); 67 | newEdge_piece->setOppositeEdge(newEdge_origin); 68 | 69 | vector < HalfEdge * > newHalfEdgeList_piece; 70 | vector < HalfEdge * > newHalfEdgeList_origin; 71 | 72 | for (ll j = lastVertex_origin;;) { 73 | newHalfEdgeList_origin.push_back(origin->exterior_boundary_edge(j)); 74 | j++; 75 | if (j == origin_size) j = 0; 76 | if (j == firstVertex_origin) break; 77 | } 78 | newHalfEdgeList_origin.push_back(newEdge_origin); 79 | 80 | for (ll j = lastVertex_piece;;) { 81 | newHalfEdgeList_piece.push_back(piece->exterior_boundary_edge(j)); 82 | j++; 83 | if (j == piece_size) j = 0; 84 | if (j == firstVertex_piece) break; 85 | } 86 | newHalfEdgeList_piece.push_back(newEdge_piece); 87 | 88 | // check polygon after simplification 89 | Wall::TriangulatedSurface* pSurface = new Wall::TriangulatedSurface(); 90 | pSurface->setExteriorBoundary(newHalfEdgeList_piece); 91 | Plane_3 planeRef = TM2IN::detail::cgal::make_simple_plane(piece->normal); 92 | vector point2dList = TM2IN::detail::cgal::project_to_plane(pSurface->getVerticesList(), planeRef); 93 | Polygon_2 polygon = TM2IN::detail::cgal::make_CGAL_polygon(point2dList); 94 | if (!polygon.is_simple() || polygon.orientation() == -1) { 95 | cerr << "cannot be simplified" << endl; 96 | return 1; 97 | } 98 | 99 | origin->setExteriorBoundary(newHalfEdgeList_origin); 100 | origin->updateMBB(); 101 | piece->setExteriorBoundary(newHalfEdgeList_piece); 102 | piece->updateMBB(); 103 | 104 | return 0; 105 | } 106 | } 107 | } 108 | } -------------------------------------------------------------------------------- /detail/algorithm/simplify_share_edges.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 20. 3 | // 4 | 5 | #ifndef TM2IN_SIMPLIFY_SHARE_EDGES_H 6 | #define TM2IN_SIMPLIFY_SHARE_EDGES_H 7 | 8 | #include "features/Wall/Surface.h" 9 | #include 10 | 11 | using namespace TM2IN::Wall; 12 | using namespace std; 13 | 14 | namespace TM2IN{ 15 | namespace detail{ 16 | namespace algorithm{ 17 | /** 18 | * @ingroup imp_details 19 | */ 20 | int simplify_share_edges(Wall::TriangulatedSurface* sf1, Wall::TriangulatedSurface* sf2); 21 | } 22 | } 23 | } 24 | #endif //TM2IN_SIMPLIFY_SHARE_EDGES_H 25 | -------------------------------------------------------------------------------- /detail/algorithm/surface_neighbor.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 19. 3 | // 4 | 5 | #include "surface_neighbor.h" 6 | #include "features/Wall/TriangulatedSurface.h" 7 | 8 | namespace TM2IN{ 9 | namespace detail{ 10 | namespace algorithm{ 11 | int isNeighbor(Wall::Surface *origin, Wall::Surface *piece) { 12 | int share_count = 0; 13 | for (HalfEdge* he : origin->getExteriorBoundary()){ 14 | if (he->oppositeEdge != NULL && he->oppositeEdge->parent == piece) share_count++; 15 | } 16 | return share_count; 17 | } 18 | 19 | bool findShareVertex(vector& vi, vector& vj, ll& middle_i, ll& middle_j){ 20 | ll piece_size = vi.size(); 21 | ll origin_size = vj.size(); 22 | 23 | for (ll i = 0 ; i < piece_size ;i++){ 24 | for (ll j = origin_size - 1 ; j >= 0 ; j--){ 25 | if (vi[i] == vj[j]){ 26 | ll next_i = i + 1 == piece_size? 0 : i+1; 27 | ll next_j = j-1 == -1? origin_size-1 : j-1; 28 | if (vi[next_i] == vj[next_j]){ 29 | middle_i = i; 30 | middle_j = j; 31 | return true; 32 | } 33 | } 34 | } 35 | } 36 | 37 | return false; 38 | } 39 | 40 | int findStartAndEnd(vector& vi, vector& vj, ll middle_i, ll middle_j, ll& start_i, ll& end_i, ll& start_j, ll& end_j){ 41 | ll piece_size = (ll)vi.size(); 42 | ll origin_size = (ll)vj.size(); 43 | 44 | ll i = middle_i, j = middle_j; 45 | 46 | ll next_i = i + 1 == piece_size? 0 : i+1; 47 | ll next_j = j-1 == -1? origin_size-1 : j-1; 48 | 49 | while (vi[next_i] == vj[next_j]) 50 | { 51 | if (next_i == middle_i || next_j == middle_j){ 52 | return 1; 53 | } 54 | 55 | i = next_i; 56 | j = next_j; 57 | 58 | next_i = i + 1 == piece_size? 0 : i + 1; 59 | next_j = j - 1 == -1? origin_size-1 : j - 1; 60 | } 61 | end_i = i; 62 | start_j = j; 63 | 64 | i = middle_i; 65 | j = middle_j; 66 | 67 | next_i = i - 1 == -1? piece_size -1 : i - 1; 68 | next_j = j + 1 == origin_size? 0 : j + 1; 69 | 70 | while (vi[next_i] == vj[next_j]) 71 | { 72 | if (next_i == middle_i || next_j == middle_j){ 73 | return 1; 74 | } 75 | 76 | i = next_i; 77 | j = next_j; 78 | 79 | next_i = i - 1 == -1? piece_size -1 : i - 1; 80 | next_j = j + 1 == origin_size? 0 : j + 1; 81 | } 82 | start_i = i; 83 | end_j = j; 84 | return 0; 85 | } 86 | 87 | int constructNeighborInfo(Surface * piece, Surface * origin, neighbor_info & ni) { 88 | vector origin_vertex_list = origin->getVerticesList(); 89 | vector piece_vertex_list = piece->getVerticesList(); 90 | 91 | ll piece_middle = -1, origin_middle = -1; 92 | if (!findShareVertex(piece_vertex_list, origin_vertex_list, piece_middle, origin_middle)) return 1; 93 | 94 | ll lastVertex_piece = -1, lastVertex_origin = -1; 95 | ll firstVertex_piece = -1, firstVertex_origin = -1; 96 | 97 | int result = findStartAndEnd(piece_vertex_list, origin_vertex_list, piece_middle, origin_middle, firstVertex_piece, lastVertex_piece, firstVertex_origin, lastVertex_origin); 98 | if (result) return 1; 99 | 100 | ni.firstVertex_origin = firstVertex_origin; 101 | ni.firstVertex_piece = firstVertex_piece; 102 | ni.lastVertex_origin = lastVertex_origin; 103 | ni.lastVertex_piece = lastVertex_piece; 104 | 105 | return 0; 106 | } 107 | 108 | 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /detail/algorithm/surface_neighbor.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 19. 3 | // 4 | 5 | #ifndef TM2IN_SURFACE_NEIGHBOR_H 6 | #define TM2IN_SURFACE_NEIGHBOR_H 7 | 8 | #include "features/Wall/Surface.h" 9 | #include "features/HalfEdge.h" 10 | 11 | using namespace std; 12 | using namespace TM2IN::Wall; 13 | 14 | namespace TM2IN{ 15 | namespace detail{ 16 | namespace algorithm{ 17 | struct neighbor_info{ 18 | ll lastVertex_piece = -1; 19 | ll lastVertex_origin = -1; 20 | ll firstVertex_piece = -1; 21 | ll firstVertex_origin = -1; 22 | }; 23 | 24 | /** 25 | * @ingroup imp_details 26 | */ 27 | int isNeighbor(Wall::Surface *, Wall::Surface *); 28 | /** 29 | * @ingroup imp_details 30 | */ 31 | int constructNeighborInfo(Wall::Surface* , Wall::Surface* , neighbor_info&); 32 | 33 | /** 34 | * @ingroup imp_details 35 | */ 36 | int findStartAndEnd(vector& vi, vector& vj, ll middle_i, ll middle_j, ll& start_i, ll& end_i, ll& start_j, ll& end_j); 37 | /** 38 | * @ingroup imp_details 39 | */ 40 | bool findShareVertex(vector& vi, vector& vj, ll& middle_i, ll& middle_j); 41 | } 42 | } 43 | } 44 | 45 | #endif //TM2IN_SURFACE_NEIGHBOR_H 46 | -------------------------------------------------------------------------------- /detail/algorithm/triangulate_surface.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 20. 3 | // 4 | 5 | #include "features/Wall/Surface.h" 6 | #include "features/Wall/Triangle.h" 7 | #include "triangulate_surface.h" 8 | 9 | namespace TM2IN { 10 | namespace detail { 11 | namespace algorithm { 12 | int triangulate_surface(TM2IN::Wall::Surface *pSurface, vector &result) { 13 | std::vector vertexList = pSurface->getVerticesList(); 14 | // convert 3D point to 2D 15 | Plane_3 planeRef = TM2IN::detail::cgal::make_simple_plane(pSurface->normal); 16 | vector point2dList = TM2IN::detail::cgal::project_to_plane(pSurface->getVerticesList(), planeRef); 17 | 18 | // partition Surface to convex 2D polygons. 19 | Polygon_2 polygon = TM2IN::detail::cgal::make_CGAL_polygon(point2dList); 20 | if (!polygon.is_simple()) 21 | { 22 | cerr << "polygon is not simple" << endl; 23 | cerr << pSurface->asJsonText() << endl; 24 | cerr << polygon << endl; 25 | return 1; 26 | } 27 | if (polygon.orientation() == -1){ 28 | cerr << polygon << endl; 29 | cerr << polygon.orientation() << endl; 30 | return 1; 31 | } 32 | 33 | vector polygonList = TM2IN::detail::cgal::convexPartition(polygon); 34 | 35 | vector triangles; 36 | for (int i = 0 ; i < polygonList.size() ; i++){ 37 | CGAL_assertion(polygonList[i].is_simple() && polygonList[i].is_convex()); 38 | 39 | Polygon_2 p = polygonList[i]; 40 | vector points; 41 | for (Polygon_2::Vertex_iterator vi = p.vertices_begin(); vi != p.vertices_end(); ++vi){ 42 | Point_2 point2d(vi->x(), vi->y()); 43 | points.push_back(point2d); 44 | } 45 | 46 | Delaunay T; 47 | T.insert(points.begin(),points.end()); 48 | for(Delaunay::Finite_faces_iterator fit = T.finite_faces_begin(); 49 | fit != T.finite_faces_end(); ++fit) 50 | { 51 | vector localTemp; 52 | Delaunay::Face_handle facet = fit; 53 | 54 | for (int j = 0 ; j < 3 ; j++){ 55 | Point_2 point2d = facet->vertex(j)->point(); 56 | int k; 57 | for (k = 0 ; k < point2dList.size() ; k++){ 58 | if (point2d == point2dList[k]) break; 59 | } 60 | if (k == point2dList.size()){ 61 | cerr << "new Point" << endl; 62 | exit(-1); 63 | } 64 | localTemp.push_back(vertexList[k]); 65 | } 66 | TM2IN::Wall::Triangle* new_tri = new TM2IN::Wall::Triangle(localTemp); 67 | new_tri->geom_id = pSurface->geom_id + "_" + to_string(triangles.size()); 68 | triangles.push_back(new_tri); 69 | } 70 | } 71 | result = triangles; 72 | 73 | return 0; 74 | } 75 | } 76 | } 77 | } -------------------------------------------------------------------------------- /detail/algorithm/triangulate_surface.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 20. 3 | // 4 | 5 | #ifndef TM2IN_TRIANGULATE_SURFACE_H 6 | #define TM2IN_TRIANGULATE_SURFACE_H 7 | 8 | #include "features/IndoorComponent.h" 9 | #include "detail/cgal_config.h" 10 | #include "detail/cgal/plane.h" 11 | #include "detail/cgal/polygon.h" 12 | 13 | namespace TM2IN { 14 | namespace detail { 15 | namespace algorithm { 16 | /** 17 | * @ingroup imp_details 18 | * @brief Triangulate Wall::Surface to a vector of Wall::Triangle. 0 is succeed. 1 is fail. 19 | * 20 | */ 21 | int triangulate_surface(TM2IN::Wall::Surface* sf, vector& result); 22 | } 23 | } 24 | } 25 | 26 | #endif //TM2IN_TRIANGULATE_SURFACE_H 27 | -------------------------------------------------------------------------------- /detail/cgal/geometry.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 23. 3 | // 4 | 5 | #include "geometry.h" 6 | 7 | 8 | namespace TM2IN { 9 | namespace detail { 10 | namespace cgal { 11 | bool has_bbox_intersect(IndoorComponent *s1, IndoorComponent *s2){ 12 | CGAL::Bbox_3 b1 = s1->getMBB(); 13 | CGAL::Bbox_3 b2 = s2->getMBB(); 14 | return CGAL::do_intersect(b1,b2); 15 | } 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /detail/cgal/geometry.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 23. 3 | // 4 | 5 | #ifndef TM2IN_GEOMETRY_H 6 | #define TM2IN_GEOMETRY_H 7 | 8 | #include "features/IndoorComponent.h" 9 | 10 | namespace TM2IN { 11 | namespace detail { 12 | namespace cgal { 13 | /** 14 | * @ingroup imp_details 15 | * @brief Chekcs Bbox_3 intersects 16 | */ 17 | bool has_bbox_intersect(IndoorComponent *s1, IndoorComponent *s2); 18 | } 19 | } 20 | } 21 | 22 | #endif //TM2IN_GEOMETRY_H 23 | -------------------------------------------------------------------------------- /detail/cgal/plane.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 19. 3 | // 4 | 5 | #include "plane.h" 6 | #include "features/Vertex.h" 7 | #include "cgal/vector_angle.h" 8 | #include "vector_3.h" 9 | 10 | namespace TM2IN { 11 | namespace detail { 12 | namespace cgal{ 13 | Plane_3 make_PCA_plane(std::vector < Vertex * > vertices, Vector_3 normal) { 14 | std::vector cgal_points; 15 | for (int i = 0; iCGAL_point()); 17 | } 18 | Plane_3 plane; 19 | linear_least_squares_fitting_3(cgal_points.begin(), cgal_points.end(), plane, CGAL::Dimension_tag<0>()); 20 | 21 | Vector_3 planeVector = plane.orthogonal_vector(); 22 | CGAL_assertion(normal!= CGAL::NULL_VECTOR); 23 | if (TM2IN::cgal::getAngle(planeVector, normal) > 90) { 24 | return plane.opposite(); 25 | } 26 | else 27 | return plane; 28 | } 29 | 30 | Plane_3 make_simple_plane(Vector_3 pNormal) { 31 | std::vector simple_normal_vector_list6 = { 32 | Vector_3(1,0,0), //0, 3 33 | Vector_3(0,1,0), 34 | Vector_3(0,0,1), 35 | Vector_3(-1,0,0), 36 | Vector_3(0,-1,0), 37 | Vector_3(0,0,-1) 38 | }; 39 | 40 | int type = TM2IN::detail::cgal::find_closest_vector(pNormal, simple_normal_vector_list6); 41 | Vector_3 normal = simple_normal_vector_list6[type]; 42 | Point_3 origin(0,0,0); 43 | Plane_3 plane3(origin, normal); 44 | return plane3; 45 | } 46 | 47 | std::vector project_to_plane(std::vector vertexList, Plane_3 plane) { 48 | std::vector pointList; 49 | for (int i = 0 ; i < vertexList.size(); i++){ 50 | Point_2 point2d = plane.to_2d(vertexList[i]->CGAL_point()); 51 | pointList.push_back(point2d); 52 | } 53 | return pointList; 54 | } 55 | } 56 | 57 | } 58 | 59 | 60 | } -------------------------------------------------------------------------------- /detail/cgal/plane.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 19. 3 | // 4 | 5 | #ifndef TM2IN_PCA_H 6 | #define TM2IN_PCA_H 7 | 8 | #include 9 | 10 | #include "features/IndoorComponent.h" 11 | #include "detail/cgal_config.h" 12 | 13 | namespace TM2IN { 14 | namespace detail { 15 | namespace cgal { 16 | /** 17 | * @ingroup imp_details 18 | * @brief Creates PCA plane with Vertex and normal vector 19 | */ 20 | Plane_3 make_PCA_plane(std::vector vertices, Vector_3 normal); 21 | /** 22 | * @ingroup imp_details 23 | */ 24 | Plane_3 make_simple_plane(Vector_3 pNormal); 25 | /** 26 | * @ingroup imp_details 27 | * @brief Projects Vertex list to plane and returns a vector of Kernel::Point_2 28 | */ 29 | std::vector project_to_plane(std::vector vertexList, Plane_3 plane); 30 | } 31 | } 32 | } 33 | 34 | #endif //TM2IN_PCA_H 35 | -------------------------------------------------------------------------------- /detail/cgal/polygon.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 19. 3 | // 4 | 5 | #include "polygon.h" 6 | 7 | 8 | namespace TM2IN { 9 | namespace detail { 10 | namespace cgal { 11 | Polygon_2 make_CGAL_polygon(vector surface2D) { 12 | Polygon_2 polygon; 13 | for (int i = 0 ; i < surface2D.size() ; i++){ 14 | Traits::Point_2 pt(surface2D[i].x(), surface2D[i].y()); 15 | polygon.push_back(pt); 16 | } 17 | return polygon; 18 | } 19 | 20 | vector convexPartition(Polygon_2 polygon) { 21 | vector partitionPolygon; 22 | CGAL::approx_convex_partition_2(polygon.vertices_begin(), polygon.vertices_end(), std::back_inserter(partitionPolygon)); 23 | return partitionPolygon; 24 | } 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /detail/cgal/polygon.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 19. 3 | // 4 | 5 | #ifndef TM2IN_POLYGON_H 6 | #define TM2IN_POLYGON_H 7 | 8 | #include "detail/cgal_config.h" 9 | #include 10 | 11 | using namespace std; 12 | 13 | namespace TM2IN { 14 | namespace detail { 15 | namespace cgal { 16 | /** 17 | * @ingroup imp_details 18 | * @brief Generates CGAL::Polygon_2 19 | */ 20 | Polygon_2 make_CGAL_polygon(vector surface2D); 21 | /** 22 | * @ingroup imp_details 23 | * @brief Partitions Polygon_2 to a vector of Polygon_2 24 | */ 25 | vector convexPartition(Polygon_2 polygon); 26 | } 27 | } 28 | } 29 | 30 | #endif //TM2IN_POLYGON_H 31 | 32 | -------------------------------------------------------------------------------- /detail/cgal/type_conversion.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 19. 3 | // 4 | 5 | #include "type_conversion.h" 6 | 7 | #include "features/HalfEdge.h" 8 | #include "features/Vertex.h" 9 | #include "features/Wall/Triangle.h" 10 | 11 | namespace TM2IN { 12 | namespace detail { 13 | namespace cgal { 14 | Kernel::Point_3 to_CGAL_Point_3(Vertex &v) { 15 | return Point_3(v.x(),v.y(),v.z());; 16 | } 17 | 18 | Kernel::Triangle_3 to_CGAL_Triangle_3(Wall::Triangle &tri) { 19 | Point_3 p1 = tri.vertex(0)->CGAL_point(); 20 | Point_3 p2 = tri.vertex(1)->CGAL_point(); 21 | Point_3 p3 = tri.vertex(2)->CGAL_point(); 22 | 23 | Triangle_3 cgal_triangle(p1,p2,p3); 24 | return cgal_triangle; 25 | } 26 | 27 | Segment_3 to_CGAL_Segment_3(HalfEdge *he) { 28 | Point_3 p1 = he->vertices[0]->CGAL_point(); 29 | Point_3 p2 = he->vertices[1]->CGAL_point(); 30 | Segment_3 seg(p1, p2); 31 | return seg; 32 | } 33 | 34 | Bbox_3 to_CGAL_bbox3(MinimumBoundingBox &box) { 35 | return Bbox_3(box.min(0), box.min(1), box.min(2), box.max(0), box.max(1), box.max(2)); 36 | } 37 | 38 | Bbox_3 create_bbox3(double min_coords[3], double max_coords[3]) { 39 | return Bbox_3(min_coords[0], min_coords[1], min_coords[2], max_coords[0], max_coords[1], max_coords[2]); 40 | } 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /detail/cgal/type_conversion.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 19. 3 | // 4 | 5 | #ifndef TM2IN_TYPE_CONVERSION_H 6 | #define TM2IN_TYPE_CONVERSION_H 7 | 8 | #include "features/IndoorComponent.h" 9 | #include "detail/cgal_config.h" 10 | 11 | namespace TM2IN{ 12 | namespace detail{ 13 | namespace cgal{ 14 | /** 15 | * @ingroup imp_details 16 | * @brief Vertex to CGAL Point_3 17 | */ 18 | Kernel::Point_3 to_CGAL_Point_3(Vertex& vt); 19 | /** 20 | * @ingroup imp_details 21 | * @brief Wall::Triangle to CGAL Triangle_3 22 | */ 23 | Kernel::Triangle_3 to_CGAL_Triangle_3(Wall::Triangle& tri); 24 | /** 25 | * @ingroup imp_details 26 | * @brief HalfEdge to CGAL Segment_3 27 | */ 28 | Segment_3 to_CGAL_Segment_3(HalfEdge* he); 29 | /** 30 | * @ingroup imp_details 31 | * @brief MinimumBoundingBox to CGAL Bbox_3 32 | */ 33 | Bbox_3 to_CGAL_bbox3(MinimumBoundingBox& box); 34 | 35 | Bbox_3 create_bbox3(double min_coords[3], double max_coords[3]); 36 | } 37 | } 38 | } 39 | 40 | #endif //TM2IN_TYPE_CONVERSION_H 41 | -------------------------------------------------------------------------------- /detail/cgal/vector_3.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 23. 3 | // 4 | 5 | #include 6 | #include "vector_3.h" 7 | 8 | namespace TM2IN { 9 | namespace detail { 10 | namespace cgal { 11 | double getCosineValue(Vector_3 &nv1, Vector_3 &nv2) { 12 | assert(nv1.squared_length() > 0 && nv2.squared_length() > 0); 13 | double nv1_length = sqrt(nv1.squared_length()); 14 | double nv2_length = sqrt(nv2.squared_length()); 15 | 16 | Vector_3 unit_nv1 = nv1 / nv1_length; 17 | Vector_3 unit_nv2 = nv2 / nv2_length; 18 | 19 | double inner = (unit_nv1 * unit_nv2); 20 | double cos = inner; 21 | if (cos > 0.99999) cos = 1; 22 | else if (cos < -0.99999) cos = -1; 23 | return cos; 24 | } 25 | 26 | int find_closest_vector(Vector_3 &nv, std::vector &vector_list) { 27 | int type = 0; 28 | double diff = 90.0; 29 | for (int i = 0 ; i < vector_list.size() ; i++){ 30 | double temp_diff = TM2IN::cgal::getAngle(vector_list[i], nv); 31 | if (temp_diff < diff){ 32 | diff = temp_diff; 33 | type = i; 34 | } 35 | } 36 | return type; 37 | } 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /detail/cgal/vector_3.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 23. 3 | // 4 | 5 | #ifndef TM2IN_VECTOR_3_H 6 | #define TM2IN_VECTOR_3_H 7 | 8 | #include "detail/cgal_config.h" 9 | 10 | namespace TM2IN { 11 | namespace detail { 12 | namespace cgal { 13 | /** 14 | * @ingroup imp_details 15 | * @brief Returns cosine value 16 | */ 17 | double getCosineValue(Vector_3& nv1,Vector_3& nv2); 18 | 19 | /** 20 | * @ingroup imp_details 21 | * @brief Return closest vector from nv among vector_list 22 | * 23 | */ 24 | int find_closest_vector(Vector_3& nv, std::vector& vector_list); 25 | } 26 | } 27 | } 28 | 29 | #endif //TM2IN_VECTOR_3_H 30 | -------------------------------------------------------------------------------- /detail/cgal_config.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 19. 3 | // 4 | 5 | #ifndef TM2IN_CGAL_CONFIG_H 6 | #define TM2IN_CGAL_CONFIG_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | 37 | //typedef CGAL::Simple_cartesian Kernel; 38 | typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; 39 | typedef CGAL::Aff_transformation_3 Transformation; 40 | typedef Kernel::Point_2 Point_2; 41 | typedef Kernel::Point_3 Point_3; 42 | typedef Kernel::Vector_3 Vector_3; 43 | typedef Kernel::Vector_2 Vector_2; 44 | typedef Kernel::Plane_3 Plane_3; 45 | typedef Kernel::Triangle_3 Triangle_3; 46 | typedef Kernel::Line_3 Line_3; 47 | typedef Kernel::Segment_2 Segment_2; 48 | typedef Kernel::Segment_3 Segment_3; 49 | typedef Kernel::Intersect_2 Intersect_2; 50 | typedef Kernel::Intersect_3 Intersect_3; 51 | typedef CGAL::Bbox_3 Bbox_3; 52 | 53 | typedef CGAL::Triangulation_vertex_base_with_info_2 Vb; 54 | typedef CGAL::Triangulation_data_structure_2 Tds; 55 | typedef CGAL::Delaunay_triangulation_2 Delaunay; 56 | typedef Delaunay::Point D_Point; 57 | 58 | typedef CGAL::Partition_traits_2 Traits; 59 | typedef Traits::Polygon_2 Polygon_2; 60 | typedef Traits::Point_2 Polygon_Point_2; 61 | 62 | 63 | #endif //TM2IN_CGAL_CONFIG_H 64 | -------------------------------------------------------------------------------- /detail/features/RoomFactory.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 25. 3 | // 4 | 5 | #ifndef TM2IN_ROOMFACTORY_H 6 | #define TM2IN_ROOMFACTORY_H 7 | 8 | #include "features/IndoorComponent.h" 9 | 10 | using namespace TM2IN::RoomBoundary; 11 | using namespace std; 12 | 13 | namespace TM2IN { 14 | namespace detail { 15 | /** 16 | * @ingroup imp_details 17 | * @brief Input vertices and triangles and make TM2IN::Room 18 | */ 19 | class RoomFactory { 20 | private: 21 | std::vector raw_vertices; 22 | std::vector raw_triangles; 23 | std::vector> raw_triangles_with_vertex; 24 | std::string room_name; 25 | 26 | void findAndSetNeighbor(vector& a_triangle, vector& b_triangle, int i, int a_i, int b_i); 27 | public: 28 | RoomFactory(); 29 | void pushVertex(Vertex* vt); 30 | void pushTriangle(Wall::Triangle *tri); 31 | void pushTriangle(long long a, long long b, long long c); 32 | void buildStrTriangle(); 33 | 34 | std::vector make(); 35 | 36 | bool keep_vertices = false; 37 | 38 | std::vector &getVerticesList(); 39 | 40 | void setRoomName(std::string str); 41 | 42 | std::vector paritionRoom(TriangleMesh *pMesh); 43 | 44 | bool is_furniture(TriangleMesh *&tm); 45 | void clear(); 46 | }; 47 | } 48 | } 49 | 50 | 51 | #endif //TM2IN_ROOMFACTORY_H 52 | -------------------------------------------------------------------------------- /detail/features/halfedge_string.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 24. 3 | // 4 | 5 | #include 6 | #include "features/Wall/Triangle.h" 7 | #include "features/HalfEdge.h" 8 | 9 | #include "halfedge_string.h" 10 | 11 | namespace TM2IN { 12 | namespace detail { 13 | namespace HalfEdgeString { 14 | void connectOppositeHalfEdges(std::vector & triangleList) { 15 | for (int i = 0 ; i < triangleList.size() - 1 ; i++){ 16 | if (i % 10 == 0) printProcess(i, triangleList.size(), "connect Edges"); 17 | for (int j = i + 1; j < triangleList.size() ; j++){ 18 | if (TM2IN::detail::cgal::has_bbox_intersect(triangleList[i], triangleList[j])) 19 | triangleList[i]->setNeighbor(triangleList[j]); 20 | } 21 | } 22 | } 23 | 24 | void setParent(std::vector edges, Wall::Surface *pSurface) { 25 | for (HalfEdge* edge : edges){ 26 | edge->setParent(pSurface); 27 | } 28 | } 29 | 30 | std::vector getFirstVertexList(std::vector halfEdges) { 31 | std::vector vertexList; 32 | for (int i = 0 ; i < halfEdges.size() ; i++){ 33 | vertexList.push_back(halfEdges[i]->vertices[0]); 34 | } 35 | return vertexList; 36 | } 37 | 38 | 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /detail/features/halfedge_string.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 24. 3 | // 4 | 5 | #ifndef TM2IN_HALFEDGE_STRING_H 6 | #define TM2IN_HALFEDGE_STRING_H 7 | 8 | #include 9 | #include "features/Wall/Triangle.h" 10 | 11 | using namespace TM2IN::Wall; 12 | 13 | namespace TM2IN{ 14 | namespace detail{ 15 | namespace HalfEdgeString{ 16 | /** 17 | * @ingroup imp_details 18 | * @brief Sets parents of all HalfEdge. 19 | */ 20 | void setParent(std::vector edges, Wall::Surface *pSurface); 21 | /** 22 | * @ingroup imp_details 23 | * @brief Returns a list of the start Vertex of each edges. 24 | */ 25 | std::vector getFirstVertexList(std::vector halfEdges); 26 | /** 27 | * @ingroup imp_details 28 | * @brief Build opposite edge relation in a vector of Triangle 29 | */ 30 | void connectOppositeHalfEdges(std::vector& triangleList); 31 | } 32 | } 33 | } 34 | #endif //TM2IN_HALFEDGE_STRING_H 35 | -------------------------------------------------------------------------------- /detail/io/ColladaReader.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 16. 3 | // 4 | 5 | #include "detail/io/ColladaReader.h" 6 | #include "features/Vertex.h" 7 | #include "features/Wall/Triangle.h" 8 | #include "util.h" 9 | 10 | #include 11 | #include 12 | 13 | namespace TM2IN { 14 | namespace detail { 15 | namespace io { 16 | ColladaReader::ColladaReader(std::ifstream& _ifs) : ifs(_ifs){ 17 | 18 | } 19 | 20 | std::vector ColladaReader::read() { 21 | vector rooms; 22 | 23 | rapidxml::xml_document<> doc; 24 | rapidxml::xml_node<> * root_node; 25 | vector buffer((istreambuf_iterator(this->ifs)), istreambuf_iterator()); 26 | buffer.push_back('\0'); 27 | 28 | doc.parse<0>(&buffer[0]); 29 | root_node = doc.first_node("COLLADA"); 30 | string collada_version = root_node->first_attribute("version")->value(); 31 | 32 | RoomFactory factory; 33 | for (rapidxml::xml_node<>* library_geometries_node = root_node->first_node("library_geometries") ; library_geometries_node; 34 | library_geometries_node = library_geometries_node->next_sibling("library_geometries")){ 35 | for (rapidxml::xml_node<>* geometry_node = library_geometries_node->first_node("geometry") ; geometry_node; geometry_node = geometry_node->next_sibling("geometry")){ 36 | rapidxml::xml_node<>* mesh_node = geometry_node->first_node("mesh"); 37 | if (mesh_node == NULL) exit(-1); 38 | 39 | factory.setRoomName(geometry_node->first_attribute("id")->value()); 40 | 41 | rapidxml::xml_node<>* triangles_node = mesh_node->first_node("triangles"); 42 | if (triangles_node == NULL) continue; //lines 43 | 44 | rapidxml::xml_node<>* source_node = mesh_node->first_node("source"); 45 | 46 | string position_id = queryAttributeValueInNodes(mesh_node->first_node("vertices"), "input", "semantic", "POSITION", "source"); 47 | position_id.erase(0, 1); // remove '#' 48 | 49 | for (; source_node; source_node = source_node->next_sibling("source")){ 50 | if (strcmp(source_node->first_attribute("id")->value(), position_id.c_str()) == 0) break; 51 | } 52 | 53 | // check technique_common node 54 | rapidxml::xml_node<>* technique_common_node = source_node->first_node("technique_common"); 55 | rapidxml::xml_node<>* accessor_node = technique_common_node->first_node("accessor"); 56 | assert(atoi(accessor_node->first_attribute("stride")->value()) == 3); 57 | for (rapidxml::xml_node<>* param_node = accessor_node->first_node("param"); param_node; param_node = param_node->next_sibling("param")){ 58 | assert(strcmp(param_node->first_attribute("type")->value(), "float") == 0); 59 | } 60 | int num_of_vertices = atoi(accessor_node->first_attribute("count")->value()); 61 | 62 | // get Vertex Coords 63 | rapidxml::xml_node<>* float_array_node = source_node->first_node("float_array"); 64 | string float_array_str = float_array_node->value(); 65 | std::vector float_array_strings = split(float_array_str, ' '); 66 | int float_array_count=atoi(float_array_node->first_attribute("count")->value()); 67 | for (int i = 0 ; i < float_array_count / 3; i++){ 68 | Vertex* vertex = new Vertex(stof(float_array_strings[i * 3 + 0]), stof(float_array_strings[i * 3 + 1]), stof(float_array_strings[i * 3 + 2])); 69 | factory.pushVertex(vertex); 70 | } 71 | assert(num_of_vertices == factory.getVerticesList().size()); 72 | 73 | int num_of_triangles = atoi(triangles_node->first_attribute("count")->value()); 74 | int num_of_input_nodes = 0, vertex_offset; 75 | for (rapidxml::xml_node<>* input_node = triangles_node->first_node("input") ; input_node ; input_node = input_node->next_sibling("input")){ 76 | num_of_input_nodes++; 77 | } 78 | vertex_offset = atoi(queryAttributeValueInNodes(triangles_node, "input", "semantic", "VERTEX", "offset").c_str()); 79 | 80 | string p = triangles_node->first_node("p")->value(); 81 | std::vector triangle_index_string = split(p, ' '); 82 | printf("%d\n", (int)triangle_index_string.size()); 83 | 84 | for (int i = 0 ; i < num_of_triangles; i++){ 85 | int a_index = i * 3 * (num_of_input_nodes) + (num_of_input_nodes) * 0 + vertex_offset; 86 | int b_index = i * 3 * (num_of_input_nodes) + (num_of_input_nodes) * 1 + vertex_offset; 87 | int c_index = i * 3 * (num_of_input_nodes) + (num_of_input_nodes) * 2 + vertex_offset; 88 | int a = atoi(triangle_index_string[a_index].c_str()); 89 | int b = atoi(triangle_index_string[b_index].c_str()); 90 | int c = atoi(triangle_index_string[c_index].c_str()); 91 | vector& vertices = factory.getVerticesList(); 92 | TM2IN::Wall::Triangle* triangle = new Wall::Triangle(vertices[a], vertices[b], vertices[c]); 93 | factory.pushTriangle(triangle); 94 | } 95 | vector curr_rooms = factory.make(); 96 | if (curr_rooms.size() != 0) 97 | rooms.insert(rooms.end(), curr_rooms.begin(), curr_rooms.end()); 98 | } 99 | 100 | } 101 | return rooms; 102 | } 103 | 104 | std::string ColladaReader::queryAttributeValueInNodes(rapidxml::xml_node<> *pNode, const char *childNodeName, 105 | const char *condAttributeName, const char *condAttributeValue, 106 | const char *resultAttributeName) { 107 | for (rapidxml::xml_node<>* input_node = pNode->first_node(childNodeName) ; input_node ; input_node->next_sibling(childNodeName)){ 108 | if (strcmp(input_node->first_attribute(condAttributeName)->value(),condAttributeValue) == 0){ 109 | //printf("%s\n", input_node->first_attribute("source")->value()); 110 | string id(input_node->first_attribute(resultAttributeName)->value()); 111 | return id; 112 | } 113 | } 114 | cerr << "There is no attribute to satisfy query" << endl; 115 | } 116 | 117 | } //io 118 | } //detail 119 | } -------------------------------------------------------------------------------- /detail/io/ColladaReader.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 16. 3 | // 4 | 5 | #ifndef TM2IN_COLLADAREADER_H 6 | #define TM2IN_COLLADAREADER_H 7 | 8 | #include 9 | #include "features/IndoorComponent.h" 10 | 11 | #include 12 | 13 | using namespace std; 14 | 15 | namespace TM2IN { 16 | namespace detail { 17 | namespace io { 18 | /** 19 | * @ingroup imp_details 20 | */ 21 | class ColladaReader{ 22 | public: 23 | ColladaReader(ifstream& _ifs); 24 | std::vector read(); 25 | private: 26 | ifstream& ifs; 27 | 28 | std::string queryAttributeValueInNodes(rapidxml::xml_node<> *pNode, const char *childNodeName, 29 | const char *condAttributeName, const char *condAttributeValue, 30 | const char *resultAttributeName); 31 | }; 32 | } 33 | } 34 | } 35 | 36 | #endif //TM2IN_COLLADAREADER_H 37 | -------------------------------------------------------------------------------- /detail/io/InFactoryClient.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 10. 10. 3 | // 4 | 5 | #include 6 | #include "InFactoryClient.h" 7 | #include "restclient-cpp/connection.h" 8 | #include "restclient-cpp/restclient.h" 9 | #include "JsonWriter.h" 10 | 11 | #define CREATED 201 12 | #define NOT_FOUND 404 13 | #define FOUND 302 14 | 15 | 16 | namespace TM2IN { 17 | namespace detail { 18 | namespace io { 19 | static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp) 20 | { 21 | ((std::string*)userp)->append((char*)contents, size * nmemb); 22 | return size * nmemb; 23 | } 24 | 25 | void InFactoryClient::make() { 26 | /* In windows, this will init the winsock stuff */ 27 | curl_global_init(CURL_GLOBAL_ALL); 28 | 29 | string doc_url = base_url + string("/documents/") + docId; 30 | string if_url = doc_url + "/indoorfeatures/" + ifId; 31 | string psf_url = doc_url + "/primalspacefeatures/" + psfId; 32 | 33 | string doc_json = string() + "{\n" + 34 | " \"docId\":\"" + docId +"\"" + 35 | "}"; 36 | string if_json = string() + "{\n" + 37 | " \"docId\":\"" + docId +"\", " + 38 | " \"id\":\"" + ifId +"\" " + 39 | "}"; 40 | string psf_json = string() + "{\n" + 41 | " \"docId\":\"" + docId +"\", \n" + 42 | " \"parentId\":\"" + ifId +"\", \n" + 43 | " \"id\":\"" + psfId +"\" \n" + 44 | "}"; 45 | 46 | if (rest_post(doc_url.c_str(), doc_json.c_str())) 47 | throw std::runtime_error("\n\nInFactoryClient create Document problem\n\n"); 48 | 49 | if (rest_post(if_url.c_str(), if_json.c_str())) 50 | throw std::runtime_error("\n\nInFactoryClient create Indoorfeatures problem\n\n"); 51 | 52 | if (rest_post(psf_url.c_str(), psf_json.c_str())) 53 | throw std::runtime_error("\n\nInFactoryClient create PrimalSpaceFeatures problem\n\n"); 54 | 55 | for (Room* room : this->rooms){ 56 | string cs_url = doc_url + "/cellspace/" + room->geom_id; 57 | string cs_json = room_to_cellspace(room); 58 | if (rest_post(cs_url.c_str(), cs_json.c_str())) 59 | throw std::runtime_error("\n\nInFactoryClient create CellSpace problem\n\n"); 60 | 61 | } 62 | curl_global_cleanup(); 63 | } 64 | 65 | std::string InFactoryClient::getDocumentStr() { 66 | curl_global_init(CURL_GLOBAL_ALL); 67 | string doc_url = base_url + string("/documents/") + docId; 68 | string result = rest_get(doc_url.c_str()); 69 | curl_global_cleanup(); 70 | return result; 71 | } 72 | 73 | int InFactoryClient::rest_post(const char *url, const char *json) { 74 | CURL *curl; 75 | CURLcode res; 76 | struct curl_slist *headerlist = nullptr; 77 | headerlist = curl_slist_append(headerlist, "Content-Type: application/json"); 78 | 79 | string result; 80 | /* get a curl handle */ 81 | curl = curl_easy_init(); 82 | if(curl) { 83 | curl_easy_setopt(curl, CURLOPT_URL, url); 84 | curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist); 85 | curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); 86 | curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false); 87 | 88 | /* Now specify the POST data */ 89 | curl_easy_setopt(curl, CURLOPT_POST, 1L); 90 | curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json); 91 | 92 | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); 93 | curl_easy_setopt(curl, CURLOPT_WRITEDATA, &result); 94 | 95 | res = curl_easy_perform(curl); 96 | /* Check for errors */ 97 | if(res != CURLE_OK) { 98 | fprintf(stderr, "curl_easy_perform() failed: %s\n", 99 | curl_easy_strerror(res)); 100 | return -1; 101 | } 102 | 103 | /* always cleanup */ 104 | curl_easy_cleanup(curl); 105 | } 106 | else{ 107 | return -1; 108 | } 109 | return 0; 110 | 111 | } 112 | 113 | string InFactoryClient::room_to_cellspace(Room *pRoom) { 114 | string coordinates = "\"SOLID "; 115 | coordinates += TM2IN::detail::io::room_to_wkt(*pRoom); 116 | coordinates += "\""; 117 | string cs_json; 118 | cs_json += "{\n"; 119 | cs_json += " \"docId\":\"" + docId +"\", " + 120 | " \"parentId\":\"" + psfId +"\", " + 121 | " \"id\":\"" + pRoom->geom_id +"\",\n"; 122 | cs_json += " \"geometry\": {\n"; 123 | cs_json += " \"type\" : \"Solid\",\n"; 124 | cs_json += " \"coordinates\" : " + coordinates + ",\n"; 125 | cs_json += " \"properties\" : {\n"; 126 | cs_json += " \"id\" : \"" + pRoom->geom_id +"g\",\n"; 127 | cs_json += " \"type\" : \"wkt\"\n"; 128 | cs_json += " }\n"; 129 | cs_json += "\t\t}\n"; 130 | cs_json += "\t}\n"; 131 | cs_json += "}"; 132 | return cs_json; 133 | } 134 | 135 | string InFactoryClient::rest_get(const char *url) { 136 | CURL *curl; 137 | CURLcode res; 138 | std::string readBuffer; 139 | 140 | curl = curl_easy_init(); 141 | if(curl) { 142 | curl_easy_setopt(curl, CURLOPT_URL, url); 143 | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); 144 | curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer); 145 | res = curl_easy_perform(curl); 146 | if(res != CURLE_OK) { 147 | fprintf(stderr, "curl_easy_perform() failed: %s\n", 148 | curl_easy_strerror(res)); 149 | throw std::runtime_error("\n\nInFactoryClient get Document problem\n\n"); 150 | } 151 | curl_easy_cleanup(curl); 152 | } 153 | return readBuffer; 154 | } 155 | } 156 | } 157 | } -------------------------------------------------------------------------------- /detail/io/InFactoryClient.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 10. 10. 3 | // 4 | 5 | #ifndef TM2IN_INFACTORYCLIENT_H 6 | #define TM2IN_INFACTORYCLIENT_H 7 | 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | namespace TM2IN { 14 | namespace detail { 15 | namespace io { 16 | static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp); 17 | 18 | class InFactoryClient { 19 | public: 20 | InFactoryClient(std::vector& pRooms) : rooms(pRooms){ 21 | base_url = Options::getInstance()->infactory_url; 22 | docId = Options::getInstance()->file_name; 23 | ifId = "if1"; 24 | psfId = "psf1"; 25 | } 26 | void make(); 27 | std::string getDocumentStr(); 28 | private: 29 | std::string docId; 30 | std::string ifId; 31 | std::string psfId; 32 | std::string base_url; 33 | 34 | std::vector& rooms; 35 | 36 | int rest_post(const char *url, const char *json); 37 | string rest_get(const char *url); 38 | 39 | string room_to_cellspace(Room *pRoom); 40 | }; 41 | } 42 | } 43 | } 44 | 45 | 46 | #endif //TM2IN_INFACTORYCLIENT_H 47 | -------------------------------------------------------------------------------- /detail/io/IndoorGMLWriter.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 8. 24. 3 | // 4 | 5 | #ifndef TM2IN_INDOORGMLWRITER_H 6 | #define TM2IN_INDOORGMLWRITER_H 7 | 8 | #include "rapidxml/rapidxml.hpp" 9 | #include "rapidxml/rapidxml_print.hpp" 10 | #include "rapidxml/rapidxml_utils.hpp" 11 | #include "features/IndoorComponent.h" 12 | 13 | #include 14 | 15 | using namespace std; 16 | 17 | namespace TM2IN { 18 | namespace detail { 19 | namespace io { 20 | /** 21 | * @ingroup imp_details 22 | */ 23 | class IndoorGMLWriter { 24 | public: 25 | IndoorGMLWriter(ofstream& fout) : file_stored(fout) {} 26 | int write(std::vector rooms); 27 | private: 28 | ofstream& file_stored; 29 | 30 | rapidxml::xml_node<> *create_cell_space_node(Room *pRoom, rapidxml::xml_document<>& document); 31 | 32 | rapidxml::xml_node<> * 33 | create_surface_member_node(Wall::Polygon *pPolygon, rapidxml::xml_document<> &document); 34 | 35 | }; 36 | } 37 | } 38 | } 39 | 40 | #endif //TM2IN_INDOORGMLWRITER_H 41 | -------------------------------------------------------------------------------- /detail/io/JsonWriter.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 18. 3 | // 4 | 5 | #ifndef TM2IN_JSONWRITER_H 6 | #define TM2IN_JSONWRITER_H 7 | 8 | #include 9 | #include "features/IndoorComponent.h" 10 | 11 | using namespace std; 12 | 13 | namespace TM2IN { 14 | namespace detail { 15 | namespace io { 16 | /** 17 | * @ingroup imp_details 18 | */ 19 | class JsonWriter { 20 | public : 21 | JsonWriter(std::ofstream& _fout); 22 | void write(vector &ts, int boundary_mode); 23 | private: 24 | std::ofstream& fout; 25 | bool exp_tri; 26 | }; 27 | 28 | string room_to_json(Room &ps, int boundary_mode); 29 | string surface_to_json(Wall::Surface& sf); 30 | string surface_to_json_with_triangles(Wall::TriangulatedSurface &pSurface); 31 | string vertex_to_json(Vertex& vt, string index); 32 | 33 | string room_to_wkt(Room &room); 34 | string surface_to_wkt(Wall::Surface &sf); 35 | string vertex_to_wkt(Vertex* vt); 36 | } 37 | } 38 | } 39 | 40 | 41 | #endif //TM2IN_JSONWRITER_H 42 | -------------------------------------------------------------------------------- /detail/io/Max3DSReader.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 16. 3 | // 4 | 5 | #ifndef TM2IN_MAX3DSREADER_H 6 | #define TM2IN_MAX3DSREADER_H 7 | 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | namespace TM2IN { 14 | namespace detail { 15 | namespace io { 16 | /** 17 | * @ingroup imp_details 18 | */ 19 | class Max3DSReader { 20 | public: 21 | Max3DSReader(FILE* _fp); 22 | std::vector read(); 23 | private: 24 | FILE* fp; 25 | long filelength(int f); 26 | }; 27 | } 28 | } 29 | } 30 | 31 | 32 | 33 | //>------ tools 34 | 35 | //>------ Id Chunk 36 | 37 | #define MAIN3DS 0x4D4D 38 | 39 | //>------ Main Chunks 40 | 41 | #define EDIT3DS 0x3D3D // this is the start of the editor config 42 | #define KEYF3DS 0xB000 // this is the start of the keyframer config 43 | 44 | //>------ sub defines of EDIT3DS 45 | 46 | #define EDIT_MATERIAL 0xAFFF 47 | #define EDIT_CONFIG1 0x0100 48 | #define EDIT_CONFIG2 0x3E3D 49 | #define EDIT_VIEW_P1 0x7012 50 | #define EDIT_VIEW_P2 0x7011 51 | #define EDIT_VIEW_P3 0x7020 52 | #define EDIT_VIEW1 0x7001 53 | #define EDIT_BACKGR 0x1200 54 | #define EDIT_AMBIENT 0x2100 55 | #define EDIT_OBJECT 0x4000 56 | 57 | #define EDIT_UNKNW01 0x1100 58 | #define EDIT_UNKNW02 0x1201 59 | #define EDIT_UNKNW03 0x1300 60 | #define EDIT_UNKNW04 0x1400 61 | #define EDIT_UNKNW05 0x1420 62 | #define EDIT_UNKNW06 0x1450 63 | #define EDIT_UNKNW07 0x1500 64 | #define EDIT_UNKNW08 0x2200 65 | #define EDIT_UNKNW09 0x2201 66 | #define EDIT_UNKNW10 0x2210 67 | #define EDIT_UNKNW11 0x2300 68 | #define EDIT_UNKNW12 0x2302 // new chunk type 69 | #define EDIT_UNKNW13 0x3000 70 | #define EDIT_UNKNW14 0xAFFF 71 | 72 | //>------ sub defines of EDIT_MATERIAL 73 | #define MAT_NAME01 0xA000 //> includes name (see mli doc for materials) 74 | 75 | //>------ sub defines of EDIT_OBJECT 76 | 77 | #define OBJ_TRIMESH 0x4100 78 | #define OBJ_LIGHT 0x4600 79 | #define OBJ_CAMERA 0x4700 80 | 81 | #define OBJ_UNKNWN01 0x4010 82 | #define OBJ_UNKNWN02 0x4012 //>>---- Could be shadow 83 | 84 | //>------ sub defines of OBJ_CAMERA 85 | #define CAM_UNKNWN01 0x4710 // new chunk type 86 | #define CAM_UNKNWN02 0x4720 // new chunk type 87 | 88 | //>------ sub defines of OBJ_LIGHT 89 | #define LIT_OFF 0x4620 90 | #define LIT_SPOT 0x4610 91 | #define LIT_UNKNWN01 0x465A 92 | 93 | //>------ sub defines of OBJ_TRIMESH 94 | #define TRI_VERTEXL 0x4110 95 | #define TRI_FACEL2 0x4111 // unknown yet 96 | #define TRI_FACEL1 0x4120 97 | #define TRI_SMOOTH 0x4150 98 | #define TRI_LOCAL 0x4160 99 | #define TRI_VISIBLE 0x4165 100 | 101 | //>>------ sub defs of KEYF3DS 102 | 103 | #define KEYF_UNKNWN01 0xB009 104 | #define KEYF_UNKNWN02 0xB00A 105 | #define KEYF_FRAMES 0xB008 106 | #define KEYF_OBJDES 0xB002 107 | 108 | #define KEYF_OBJHIERARCH 0xB010 109 | #define KEYF_OBJDUMMYNAME 0xB011 110 | #define KEYF_OBJUNKNWN01 0xB013 111 | #define KEYF_OBJUNKNWN02 0xB014 112 | #define KEYF_OBJUNKNWN03 0xB015 113 | #define KEYF_OBJPIVOT 0xB020 114 | #define KEYF_OBJUNKNWN04 0xB021 115 | #define KEYF_OBJUNKNWN05 0xB022 116 | 117 | //>>------ these define the different color chunk types 118 | #define COL_RGB 0x0010 119 | #define COL_TRU 0x0011 120 | #define COL_UNK 0x0013 // unknown 121 | 122 | //>>------ defines for viewport chunks 123 | 124 | #define TOP 0x0001 125 | #define BOTTOM 0x0002 126 | #define LEFT 0x0003 127 | #define RIGHT 0x0004 128 | #define FRONT 0x0005 129 | #define BACK 0x0006 130 | #define USER 0x0007 131 | #define CAMERA 0x0008 // 0xFFFF is the code read from file 132 | #define LIGHT 0x0009 133 | #define DISABLED 0x0010 134 | #define BOGUS 0x0011 135 | 136 | 137 | #endif //TM2IN_MAX3DSREADER_H 138 | -------------------------------------------------------------------------------- /detail/io/Max3DSWriter.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 19. 3 | // 4 | 5 | #include "Max3DSWriter.h" 6 | #include "Max3DSReader.h" 7 | 8 | #include "features/Room.h" 9 | #include "features/RoomBoundary/TriangleMesh.h" 10 | #include "features/Vertex.h" 11 | #include "features/Wall/Triangle.h" 12 | 13 | using namespace std; 14 | 15 | namespace TM2IN{ 16 | namespace detail{ 17 | namespace io{ 18 | int Max3DSWriter::write(vector rooms) { 19 | 20 | unsigned short chunk_id = 0x4D4D; 21 | unsigned int chunk_length = 0; 22 | fwrite(&chunk_id, 2, 1, pFile); 23 | fwrite(&chunk_length, 4, 1, pFile); 24 | 25 | chunk_id = 0x3D3D; 26 | chunk_length = 0; 27 | fwrite(&chunk_id, 2, 1, pFile); 28 | fwrite(&chunk_length, 4, 1, pFile); 29 | unsigned int wholeLength = 0; 30 | 31 | for (int groupI = 0 ; groupI < rooms.size(); groupI++){ 32 | Room* room = rooms[groupI]; 33 | RoomBoundary::TriangleMesh* tm = room->getTm_boundary(); 34 | vector triangles = tm->getTriangleList(); 35 | vector vertices = tm->extractVerticesList(); 36 | vector> triangleIndicies; 37 | for (int triI = 0 ; triI < triangles.size(); triI++){ 38 | Wall::Triangle* triangle = triangles[triI]; 39 | vector triangleIndex; 40 | for (int vi = 0 ; vi < 3 ; vi++){ 41 | Vertex* vt = triangle->vertex(vi); 42 | int index = 0; 43 | for (; index < vertices.size(); index++){ 44 | if (vertices[index] == vt) 45 | break; 46 | } 47 | assert (vertices.size() != index); 48 | triangleIndex.push_back(index); 49 | } 50 | triangleIndicies.push_back(triangleIndex); 51 | } 52 | 53 | unsigned int VERTICES_LIST_LENGTH = sizeof(unsigned short) + sizeof(unsigned int) + // Vertex : chunk_id and chunk_length 54 | sizeof(unsigned short) + // Vertices number 55 | sizeof(float) * 3 * vertices.size(); // Vertices List 56 | unsigned int FACES_DESCRIPTION_LENGTH = sizeof(unsigned short) + sizeof(unsigned int) + // Polygon : chunk_id and chunk_length 57 | sizeof(unsigned short) + // Polygons number 58 | sizeof(unsigned short) * 4 * triangleIndicies.size(); // Polygons List 59 | unsigned int TRIANGULAR_MESH_LENGTH = sizeof(unsigned short) + sizeof(unsigned int) + //OBJ_TRIMESH 60 | VERTICES_LIST_LENGTH + FACES_DESCRIPTION_LENGTH; 61 | 62 | chunk_id = EDIT_OBJECT; 63 | chunk_length = sizeof(unsigned short) + sizeof(unsigned int) + 64 | (unsigned short)room->geom_id.size() + 1 + 65 | // Triangle Mesh : chunk_id and chunk_length 66 | TRIANGULAR_MESH_LENGTH; 67 | wholeLength += chunk_length; 68 | 69 | fwrite(&chunk_id, 2, 1, pFile); 70 | fwrite(&chunk_length, 4, 1, pFile); 71 | 72 | const char* name = room->geom_id.c_str(); 73 | for (int i = 0 ; name[i] != 0 ; i++){ 74 | fwrite(&name[i], sizeof(char), 1, pFile); 75 | } 76 | char temp = 0; 77 | fwrite(&temp, sizeof(char),1, pFile); //NULL 78 | 79 | // Triangle Mesh 80 | chunk_id = OBJ_TRIMESH; 81 | chunk_length = TRIANGULAR_MESH_LENGTH; 82 | fwrite(&chunk_id, 2, 1, pFile); 83 | fwrite(&chunk_length, 4, 1, pFile); 84 | 85 | // Vertices List 86 | chunk_id = TRI_VERTEXL; 87 | chunk_length = VERTICES_LIST_LENGTH; 88 | fwrite(&chunk_id, 2, 1, pFile); 89 | fwrite(&chunk_length, 4, 1, pFile); 90 | unsigned short sizeOfVertices = (unsigned short)vertices.size(); 91 | fwrite(&sizeOfVertices, sizeof(unsigned short), 1, pFile); 92 | for (int vi = 0 ; vi < vertices.size(); vi++){ 93 | float x = (float)vertices[vi]->x(); 94 | float y = (float)vertices[vi]->y(); 95 | float z = (float)vertices[vi]->z(); 96 | fwrite(&x, sizeof(float), 1, pFile); 97 | fwrite(&y, sizeof(float), 1, pFile); 98 | fwrite(&z, sizeof(float), 1, pFile); 99 | } 100 | 101 | // Triangle List 102 | chunk_id = TRI_FACEL1; 103 | chunk_length = FACES_DESCRIPTION_LENGTH; 104 | fwrite(&chunk_id, 2, 1, pFile); 105 | fwrite(&chunk_length, 4, 1, pFile); 106 | unsigned short sizeOfTriangles = (unsigned short)triangleIndicies.size(); 107 | fwrite(&sizeOfTriangles, sizeof(unsigned short), 1, pFile); 108 | for (int tr = 0 ; tr < triangleIndicies.size(); tr++){ 109 | for (int i = 0 ; i < 3 ; i++){ 110 | fwrite(&triangleIndicies[tr][i], sizeof(unsigned short), 1, pFile); 111 | } 112 | unsigned short temp = 1; 113 | fwrite(&temp, sizeof(unsigned short), 1, pFile); 114 | } 115 | } 116 | 117 | fseek(pFile, sizeof(unsigned short) * 2 + sizeof(unsigned int), SEEK_SET); 118 | wholeLength += sizeof(unsigned short) + sizeof(unsigned int); 119 | fwrite(&wholeLength, sizeof(unsigned short), 1, pFile); 120 | 121 | fseek(pFile, sizeof(unsigned short) , SEEK_SET); 122 | wholeLength += sizeof(unsigned short) + sizeof(unsigned int); 123 | fwrite(&wholeLength, sizeof(unsigned short), 1, pFile); 124 | 125 | fclose(pFile); 126 | 127 | return 0; 128 | } 129 | 130 | Max3DSWriter::Max3DSWriter(FILE *pFile) : pFile(pFile) { } 131 | 132 | } 133 | } 134 | } 135 | 136 | 137 | -------------------------------------------------------------------------------- /detail/io/Max3DSWriter.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 19. 3 | // 4 | 5 | #ifndef TM2IN_MAX3DSWRITER_H 6 | #define TM2IN_MAX3DSWRITER_H 7 | 8 | #include 9 | #include "features/IndoorComponent.h" 10 | 11 | namespace TM2IN { 12 | namespace detail { 13 | namespace io { 14 | /** 15 | * @ingroup imp_details 16 | */ 17 | class Max3DSWriter { 18 | public: 19 | Max3DSWriter(FILE* pFile); 20 | int write(std::vector rooms); 21 | private: 22 | FILE* pFile; 23 | }; 24 | } 25 | } 26 | } 27 | 28 | #endif //TM2IN_MAX3DSWRITER_H 29 | -------------------------------------------------------------------------------- /detail/io/TVRReader.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 16. 3 | // 4 | 5 | #include "TVRReader.h" 6 | 7 | #include "features/Room.h" 8 | #include "detail/features/RoomFactory.h" 9 | #include "features/Vertex.h" 10 | #include "features/Wall/Triangle.h" 11 | 12 | namespace TM2IN { 13 | namespace detail { 14 | namespace io { 15 | TVRReader::TVRReader(std::ifstream &_ifs): ifs(_ifs) { 16 | 17 | } 18 | 19 | std::vector TVRReader::read() { 20 | int version = 0; 21 | string inputstr; 22 | getline(this->ifs, inputstr); 23 | if (inputstr.find("TVR0") != string::npos){ 24 | version = 0; 25 | } 26 | else if (inputstr.find("TVR1") != string::npos){ 27 | version = 1; 28 | } 29 | else{ 30 | std::runtime_error("different version : " + inputstr); 31 | } 32 | cout << "TVR Version : " << version << endl; 33 | 34 | int v_count = 0; 35 | int f_count = 0; 36 | 37 | vector rooms; 38 | RoomFactory factory; 39 | 40 | if (version == 0) 41 | factory.keep_vertices = true; 42 | else 43 | factory.keep_vertices = false; 44 | 45 | bool is_one_room = (version == 1); 46 | ull pre_vertex = 0; 47 | 48 | while(!this->ifs.eof()){ 49 | getline(this->ifs, inputstr); 50 | if (inputstr.size() < 3) continue; 51 | switch(inputstr.c_str()[0]){ 52 | case 'c':{ 53 | break; 54 | } 55 | case 'v':{ 56 | auto pt_v = this->makeVertex(inputstr); 57 | factory.pushVertex(pt_v); 58 | 59 | v_count++; 60 | if (v_count % 5000 == 0) cout << "Loaded vertices : " << v_count << endl; 61 | 62 | break; 63 | } 64 | case 'g':{ 65 | if (is_one_room){ 66 | if (f_count != 0){ 67 | pre_vertex += v_count; 68 | } 69 | else{ 70 | string group_name = this->getGroupName(inputstr); 71 | if (group_name.find('\r') != string::npos) group_name.erase(group_name.find('\r')); 72 | factory.setRoomName(group_name); 73 | } 74 | } 75 | else{ 76 | if (f_count != 0){ 77 | cout << "Building Triangle Adjacency relation" << f_count << endl; 78 | factory.buildStrTriangle(); 79 | vector curr_rooms = factory.make(); 80 | if (curr_rooms.size() != 0) 81 | rooms.insert(rooms.end(), curr_rooms.begin(), curr_rooms.end()); 82 | pre_vertex += v_count; 83 | f_count = 0; 84 | } 85 | string group_name = this->getGroupName(inputstr); 86 | if (group_name.find('\r') != string::npos) group_name.erase(group_name.find('\r')); 87 | factory.setRoomName(group_name); 88 | } 89 | break; 90 | } 91 | case 'f':{ 92 | assert(v_count != 0); 93 | 94 | //Wall::Triangle* tri = this->makeTriangle(inputstr, factory.getVerticesList()); 95 | //factory.pushTriangle(tri); 96 | 97 | std::vector x = split(inputstr, ' '); 98 | 99 | ll a = stol(x[1]) + pre_vertex; 100 | ll b = stol(x[2]) + pre_vertex; 101 | ll c = stol(x[3]) + pre_vertex; 102 | factory.pushTriangle(a, b, c); 103 | 104 | x.clear(); 105 | 106 | f_count++; 107 | if (f_count % 5000 == 0) cout << "Loaded faces : " << f_count << endl; 108 | 109 | break; 110 | } 111 | } 112 | } 113 | cout << "Building Triangle Adjacency relation... " << f_count << endl; 114 | factory.buildStrTriangle(); 115 | 116 | vector curr_rooms = factory.make(); 117 | if (curr_rooms.size() != 0) 118 | rooms.insert(rooms.end(), curr_rooms.begin(), curr_rooms.end()); 119 | return rooms; 120 | } 121 | 122 | string TVRReader::getGroupName(string& input){ 123 | std::vector x = split(input, ' '); 124 | string x_1(x[1]); 125 | x.clear(); 126 | return x_1; 127 | } 128 | 129 | Wall::Triangle* TVRReader::makeTriangle(string& input, vector& vertex){ 130 | std::vector x = split(input, ' '); 131 | 132 | ll a = stol(x[1]); 133 | ll b = stol(x[2]); 134 | ll c = stol(x[3]); 135 | 136 | auto va = vertex[a]; 137 | auto vb = vertex[b]; 138 | auto vc = vertex[c]; 139 | Wall::Triangle* newTriangle = new Wall::Triangle(va, vb, vc); 140 | 141 | x.clear(); 142 | return newTriangle; 143 | } 144 | 145 | Vertex * TVRReader::makeVertex(string &input) { 146 | std::stringstream ss; 147 | ss.str(input); 148 | 149 | string line; 150 | getline(ss, line, '\t'); 151 | std::vector strings = split(line, ' '); 152 | 153 | auto vt = new Vertex(stod(strings[1]), stod(strings[2]), stod(strings[3])); 154 | strings.clear(); 155 | 156 | return vt; 157 | } 158 | } 159 | } 160 | } -------------------------------------------------------------------------------- /detail/io/TVRReader.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 16. 3 | // 4 | 5 | #ifndef TM2IN_TVRREADER_H 6 | #define TM2IN_TVRREADER_H 7 | 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | namespace TM2IN{ 14 | namespace detail{ 15 | namespace io{ 16 | /** 17 | * @ingroup imp_details 18 | */ 19 | class TVRReader { 20 | public: 21 | TVRReader(std::ifstream& _ifs); 22 | std::vector read(); 23 | private: 24 | std::ifstream& ifs; 25 | 26 | Wall::Triangle* makeTriangle(string& input, vector& vertex); 27 | string getGroupName(string& input); 28 | Vertex *makeVertex(string &input); 29 | }; 30 | 31 | } 32 | } 33 | } 34 | 35 | 36 | #endif //TM2IN_TVRREADER_H 37 | -------------------------------------------------------------------------------- /doc/img/180920-tm2in-process.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/STEMLab/TM2IN/0fc0832ab90cbae366ce7e70a067fcbc28c40b0b/doc/img/180920-tm2in-process.gif -------------------------------------------------------------------------------- /doc/img/pipeline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/STEMLab/TM2IN/0fc0832ab90cbae366ce7e70a067fcbc28c40b0b/doc/img/pipeline.png -------------------------------------------------------------------------------- /doc/mainpage.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * @mainpage TM2IN 4 | * 5 | * @section intro_sec Introduction 6 | * 7 | * TM2IN generates appropriate Solid geometry for Indoor Map from Triangle Mesh data such as TVR, COLLADA, 3DS. 8 | * 9 | * 10 | * @section dependencies_sec Dependencies 11 | * 12 | - CGAL (http://www.cgal.org/) 13 | - SFCGAL (http://www.sfcgal.org) 14 | - Eigen3 (http://eigen.tuxfamily.org/index.php?title=Main_Page) 15 | - Boost (http://www.boost.org/) 16 | - rapidxml (http://rapidxml.sourceforge.net) 17 | * 18 | * @section geometric_features_sec Geometric Indoor Features 19 | * 20 | * @link geo_features Geometric Indoor Features @endlink 21 | * 22 | * All geometric features in TM2IN are TM2IN::IndoorComponent. 23 | * 24 | * - TM2IN::IndoorComponent 25 | * 26 | * Each TM2IN::IndoorComponent objects have TM2IN::MinimumBoundingBox. 27 | * 28 | * - TM2IN::MinimumBoundingBox 29 | * 30 | * Basic geometric features are TM2IN::Vertex and TM2IN::HalfEdge. 31 | * 32 | * - TM2IN::Vertex 33 | * - TM2IN::HalfEdge 34 | * 35 | * A list of HalfEdge constructs TM2IN::Wall. 36 | * 37 | * - TM2IN::Wall::Surface 38 | * - TM2IN::Wall::Triangle 39 | * - TM2IN::Wall::TriangulatedSurface 40 | * - TM2IN::Wall::Polygon 41 | * 42 | * A set of TM2IN::Wall constructs TM2IN::RoomBoundary. 43 | * 44 | * - TM2IN::RoomBoundary::PolygonMesh 45 | * - TM2IN::RoomBoundary::TriangleMesh 46 | * - TM2IN::RoomBoundary::TriangulatedSurfaceMesh 47 | * 48 | * A TM2IN::RoomBoundary constructs TM2IN::Room. 49 | * 50 | * - TM2IN::Room 51 | * 52 | * @section api_sec API 53 | * 54 | * There are several sets of functions separated by user level. 55 | * 56 | * Just for users who wants to use converter, see @link Converter Converter. @endlink 57 | * 58 | * Functions for light users are posted in @link public_api Public API @endlink 59 | * 60 | * Implementation details are posted in @link imp_details Details @endlink 61 | * 62 | * @section released Released 63 | * 64 | * Now released version of TM2IN.cpp and Converter.cpp is 1.0.0 65 | * 66 | * @defgroup public_api Public API 67 | * 68 | * @defgroup imp_details Details 69 | * 70 | * @defgroup geo_features Geometric Indoor Features 71 | * 72 | * @defgroup unused Unused 73 | * 74 | */ -------------------------------------------------------------------------------- /doc/usage-manual.md: -------------------------------------------------------------------------------- 1 | # TM2IN - Usage 2 | 3 | ## Command line 4 | 5 | ```commandline 6 | TM2IN --input-dir=.input/ --output-dir=.output/ input.tvr 7 | ``` 8 | 9 | ## Options 10 | 11 | 기울어진 글꼴은 flag option 입니다. 12 | 13 | | option | description | 14 | |----------|-------------------------| 15 | | input-dir | input root directory (required) | 16 | | output-dir | output root directory (required) | 17 | | version | output version name (default : "no-version") | 18 | | input-type | the type of input file. (tvr, 3ds, dae) | 19 | | *no-merge* | Surface Merging 작업을 하지 않습니다. (Input triangles 그대로 출력) | 20 | | polygonizer | select Polygonizer. 0 : do nothing, 1 : PCA Polygonize, 2 : Triangle Polygonize, 3 : Divided Polygonize | 21 | | thres1 | Threshold value 1 for merging algorithm | 22 | | thres2 | Threshold value 2 for merging algorithm | 23 | | *output-tvr* | print TVR file | 24 | | *output-3ds* | print 3DS file | 25 | | indoorGML | InFactory server url | 26 | | *output-tri* | print JSON file with triangles | 27 | | *write-process* | record process in file | 28 | | select-arch | select elements which are remained. 0 : architectural, 1 : non-architectural, 2 : all, 3 : manually choose | 29 | | *do-validation* | do validation or not | 30 | -------------------------------------------------------------------------------- /features/HalfEdge.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 1. 12. 3 | // 4 | 5 | #include 6 | #include 7 | #include "HalfEdge.h" 8 | 9 | namespace TM2IN { 10 | bool HalfEdge::isSame(HalfEdge *he) { 11 | if (this->vertices[0] == he->vertices[0]) { 12 | if (this->vertices[1] == he->vertices[1]) 13 | return true; 14 | } 15 | return false; 16 | } 17 | 18 | Wall::Surface *HalfEdge::getParent() const { 19 | return parent; 20 | } 21 | 22 | void HalfEdge::setParent(Wall::Surface *pSurface) { 23 | HalfEdge::parent = pSurface; 24 | } 25 | 26 | HalfEdge *HalfEdge::getOppositeEdge() const { 27 | return oppositeEdge; 28 | } 29 | 30 | void HalfEdge::setOppositeEdge(HalfEdge *oppositeEdge) { 31 | HalfEdge::oppositeEdge = oppositeEdge; 32 | } 33 | 34 | bool HalfEdge::can_be_opposite_edge(HalfEdge *he) { 35 | if (this->vertices[0] == he->vertices[1]) { 36 | if (this->vertices[1] == he->vertices[0]) 37 | return true; 38 | } 39 | return false; 40 | } 41 | 42 | void HalfEdge::setVertex(int i, Vertex *vt) { 43 | this->vertices[i] = vt; 44 | } 45 | 46 | Kernel::Segment_3 HalfEdge::to_CGAL_segment() { 47 | return TM2IN::detail::cgal::to_CGAL_Segment_3(this); 48 | } 49 | 50 | std::string HalfEdge::asJsonText() { 51 | std::cerr << "HalfEdge::asJsonText()" << std::endl; 52 | return std::__cxx11::string(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /features/HalfEdge.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 1. 12. 3 | // 4 | 5 | #ifndef TRIANGLEMESHCLEANER_HALFEDGE_H 6 | #define TRIANGLEMESHCLEANER_HALFEDGE_H 7 | 8 | #include "features/IndoorComponent.h" 9 | 10 | namespace TM2IN { 11 | /** 12 | * @ingroup geo_features 13 | */ 14 | class HalfEdge : public IndoorComponent { 15 | private : 16 | 17 | public: 18 | std::vector vertices; 19 | Wall::Surface *parent = NULL; 20 | HalfEdge *oppositeEdge = NULL; 21 | 22 | /** 23 | * @brief Empty HalfEdge constructor 24 | */ 25 | HalfEdge() {} 26 | 27 | /** 28 | * @brief HalfEdge constructor 29 | */ 30 | HalfEdge(Vertex *pa, Vertex *pb, Wall::Surface *pSurface){ 31 | type = TM2IN::IND_TYPE::HalfEdge; 32 | vertices.push_back(pa); 33 | vertices.push_back(pb); 34 | parent = pSurface; 35 | } 36 | 37 | /** 38 | * @brief Returns parent Surface 39 | */ 40 | Wall::Surface *getParent() const; 41 | 42 | /** 43 | * @brief Sets parent Surface 44 | */ 45 | void setParent(Wall::Surface *pSurface); 46 | 47 | /** 48 | * @brief Returns opposite HalfEdge 49 | */ 50 | HalfEdge *getOppositeEdge() const; 51 | 52 | /** 53 | * @brief Sets opposite HalfEdge 54 | */ 55 | void setOppositeEdge(HalfEdge *oppositeEdge); 56 | 57 | /** 58 | * @brief Sets the i-th Vertex 59 | */ 60 | void setVertex(int i, Vertex *vt); 61 | 62 | /** 63 | * @brief Checks whether it is same edge. 64 | */ 65 | bool isSame(HalfEdge *); 66 | /** 67 | * @brief Checks whether the other has possible opposite edge. 68 | */ 69 | bool can_be_opposite_edge(HalfEdge *); 70 | 71 | Vertex *operator[](int idx) { 72 | if (idx == 0 || idx == 1) return vertices[idx]; 73 | else { 74 | std::cerr << "HalfEdge only has two vertices" << std::endl; 75 | exit(-1); 76 | } 77 | }; 78 | 79 | /** 80 | * 81 | * @brief Converts to Kernel::Segment_3 82 | */ 83 | Kernel::Segment_3 to_CGAL_segment(); 84 | 85 | /** 86 | * @brief Returns json string 87 | */ 88 | std::string asJsonText(); 89 | }; 90 | } 91 | 92 | #endif //TRIANGLEMESHCLEANER_HALFEDGE_H 93 | -------------------------------------------------------------------------------- /features/IndoorComponent.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 23. 3 | // 4 | 5 | #include "features/IndoorComponent.h" 6 | 7 | namespace TM2IN{ 8 | CGAL::Bbox_3 IndoorComponent::getMBB() { 9 | return this->mbb; 10 | } 11 | 12 | void IndoorComponent::setMBB(CGAL::Bbox_3 _mbb) { 13 | this->mbb = _mbb; 14 | } 15 | 16 | IndoorComponent::IndoorComponent() { 17 | type = TM2IN::IND_TYPE::IndoorComponent; 18 | this->mbb = CGAL::Bbox_3(); 19 | } 20 | 21 | void IndoorComponent::updateMBB() { 22 | mbb = CGAL::Bbox_3(); 23 | } 24 | 25 | std::string IndoorComponent::asJsonText() { 26 | return std::__cxx11::string(); 27 | } 28 | 29 | void IndoorComponent::mergeMBB(IndoorComponent *gm) { 30 | CGAL::Bbox_3 bbox = gm->getMBB(); 31 | this->mbb += bbox; 32 | } 33 | } 34 | 35 | -------------------------------------------------------------------------------- /features/IndoorComponent.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 23. 3 | // 4 | 5 | #ifndef TM2IN_FEATURES_GEOMETRY_H 6 | #define TM2IN_FEATURES_GEOMETRY_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include "detail/cgal_config.h" 12 | #include "MinimumBoundingBox.h" 13 | 14 | namespace TM2IN{ 15 | namespace RoomBoundary{ 16 | class TriangleMesh; 17 | class TriangulatedSurfaceMesh; 18 | class PolygonMesh; 19 | } 20 | class Room; 21 | namespace Wall{ 22 | class Surface; 23 | class Triangle; 24 | class TriangulatedSurface; 25 | class Polygon; 26 | } 27 | class Vertex; 28 | class HalfEdge; 29 | 30 | enum class IND_TYPE { 31 | IndoorComponent, Room, RoomBoundary, TriangulatedSurface, Triangle, Polygon, HalfEdge, Vertex 32 | }; 33 | /** 34 | * @ingroup geo_features 35 | */ 36 | class IndoorComponent { 37 | protected: 38 | // MinimumBoundingBox* mbb; 39 | CGAL::Bbox_3 mbb; 40 | TM2IN::IND_TYPE type; 41 | double area = 0.0; 42 | public: 43 | std::string geom_id; 44 | 45 | IndoorComponent(); 46 | 47 | /** 48 | * @brief Returns area 49 | */ 50 | double getArea(){ 51 | return this->area; 52 | } 53 | /** 54 | * @brief Sets area 55 | */ 56 | void setArea(double _area){ 57 | this->area = _area; 58 | } 59 | /** 60 | * @brief Returns minimum bounding box 61 | */ 62 | CGAL::Bbox_3 getMBB(); 63 | 64 | /** 65 | * @brief Sets minimum bounding box 66 | */ 67 | void setMBB(CGAL::Bbox_3 _mbb) ; 68 | 69 | /** 70 | * @brief Updates MinimumBoundingBox 71 | */ 72 | virtual void updateMBB(); 73 | 74 | /** 75 | * 76 | * @brief Merges with the other IndoorComponent. 77 | */ 78 | virtual void mergeMBB(IndoorComponent* gm); 79 | 80 | /** 81 | * @brief Generates json string. 82 | */ 83 | virtual std::string asJsonText(); 84 | }; 85 | 86 | } 87 | 88 | #endif //TM2IN_FEATURES_GEOMETRY_H 89 | -------------------------------------------------------------------------------- /features/MinimumBoundingBox.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 24. 3 | // 4 | 5 | #include 6 | #include 7 | #include "MinimumBoundingBox.h" 8 | 9 | namespace TM2IN { 10 | MinimumBoundingBox::MinimumBoundingBox() { 11 | this->cgal_bbox3 = CGAL::Bbox_3(); 12 | } 13 | 14 | MinimumBoundingBox::MinimumBoundingBox(double x1, double y1, double z1, double x2, double y2, double z2) { 15 | this->cgal_bbox3 = CGAL::Bbox_3(x1,y1,z1,x2,y2,z2); 16 | } 17 | 18 | MinimumBoundingBox::MinimumBoundingBox(MinimumBoundingBox *pBox) { 19 | this->cgal_bbox3 = pBox->cgal_bbox3; 20 | } 21 | 22 | double MinimumBoundingBox::operator[](int index) { 23 | if (index == 0) 24 | return this->cgal_bbox3.xmin(); 25 | else if (index == 1) 26 | return this->cgal_bbox3.ymin(); 27 | else if (index == 2) 28 | return this->cgal_bbox3.zmin(); 29 | else if (index == 3) 30 | return this->cgal_bbox3.xmax(); 31 | else if (index == 4) 32 | return this->cgal_bbox3.ymax(); 33 | else if (index == 5) 34 | return this->cgal_bbox3.zmax(); 35 | throw std::runtime_error("MinimumBoundingBox::operator[] : out of range"); 36 | } 37 | 38 | double MinimumBoundingBox::max(int index) { 39 | if (index == 0) 40 | return this->cgal_bbox3.xmax(); 41 | else if (index == 1) 42 | return this->cgal_bbox3.ymax(); 43 | else if (index == 2) 44 | return this->cgal_bbox3.zmax(); 45 | throw std::runtime_error("MinimumBoundingBox::max(int index) : out of range"); 46 | } 47 | 48 | double MinimumBoundingBox::min(int index) { 49 | if (index == 0) 50 | return this->cgal_bbox3.xmin(); 51 | else if (index == 1) 52 | return this->cgal_bbox3.ymin(); 53 | else if (index == 2) 54 | return this->cgal_bbox3.zmin(); 55 | throw std::runtime_error("MinimumBoundingBox::max(int index) : out of range"); 56 | } 57 | 58 | void MinimumBoundingBox::set_coords(double pDouble[6]) { 59 | this->cgal_bbox3 = CGAL::Bbox_3(pDouble[0], pDouble[1], pDouble[2], pDouble[3], pDouble[4], pDouble[5]); 60 | } 61 | 62 | void MinimumBoundingBox::set(CGAL::Bbox_3 &bbox3) { 63 | this->cgal_bbox3 = bbox3; 64 | } 65 | 66 | CGAL::Bbox_3 MinimumBoundingBox::CGAL_bbox3() { 67 | if (this->cgal_bbox3 == CGAL::Bbox_3()) // need update 68 | this->cgal_bbox3 = TM2IN::detail::cgal::to_CGAL_bbox3(*this); 69 | return this->cgal_bbox3; 70 | } 71 | 72 | void MinimumBoundingBox::merge(CGAL::Bbox_3& _bbox3) { 73 | if (this->cgal_bbox3 == CGAL::Bbox_3()) // need update 74 | this->cgal_bbox3 = TM2IN::detail::cgal::to_CGAL_bbox3(*this); 75 | this->cgal_bbox3 += _bbox3; 76 | set(this->cgal_bbox3); 77 | } 78 | 79 | 80 | } -------------------------------------------------------------------------------- /features/MinimumBoundingBox.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 24. 3 | // 4 | 5 | #ifndef TM2IN_MINIMUMBOUNDINGBOX_H 6 | #define TM2IN_MINIMUMBOUNDINGBOX_H 7 | 8 | 9 | #include 10 | 11 | namespace TM2IN { 12 | /** 13 | * @ingroup geo_features 14 | */ 15 | class MinimumBoundingBox { 16 | private: 17 | CGAL::Bbox_3 cgal_bbox3; 18 | public: 19 | /** 20 | * @brief Empty MBB constructor 21 | */ 22 | MinimumBoundingBox(); 23 | /** 24 | * @brief MinimumBoundingBox constructor. 25 | */ 26 | MinimumBoundingBox(double x1, double y1, double z1, double x2, double y2, double z2); 27 | /** 28 | * @brief MinimumBoundingBox constructor 29 | */ 30 | MinimumBoundingBox(MinimumBoundingBox *pBox); 31 | 32 | /** 33 | * @brief Operator []. 0 : x, 1 : y, 2 : z 34 | */ 35 | double operator[](int index); 36 | 37 | /** 38 | * @brief Return maximum value. 0 : x, 1 : y, 2 : z 39 | */ 40 | double max(int i); 41 | /** 42 | * @brief Return minimum value. 0 : x, 1 : y, 2 : z 43 | */ 44 | double min(int i); 45 | 46 | /** 47 | * @brief Sets coordinates 48 | */ 49 | void set_coords(double pDouble[6]); 50 | 51 | /** 52 | * @brief Sets MBB by CGAL::Bbox_3 53 | */ 54 | void set(CGAL::Bbox_3 &bbox3); 55 | 56 | /** 57 | * @brief Merges with CGAL::Bbox_3 58 | */ 59 | void merge(CGAL::Bbox_3& _bbox3); 60 | 61 | /** 62 | * @brief Converts to CGAL:Bbox_3 63 | */ 64 | CGAL::Bbox_3 CGAL_bbox3(); 65 | 66 | 67 | }; 68 | } 69 | 70 | 71 | #endif //TM2IN_MINIMUMBOUNDINGBOX_H 72 | -------------------------------------------------------------------------------- /features/Room.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 25. 3 | // 4 | 5 | #include "features/RoomBoundary/TriangleMesh.h" 6 | 7 | #include "Room.h" 8 | 9 | namespace TM2IN{ 10 | Room::Room(RoomBoundary::TriangleMesh *tm) { 11 | this->tm_boundary = tm; 12 | this->type=IND_TYPE ::Room; 13 | } 14 | 15 | RoomBoundary::TriangleMesh *Room::getTm_boundary() const { 16 | return tm_boundary; 17 | } 18 | 19 | void Room::setTm_boundary(RoomBoundary::TriangleMesh *tm_boundary) { 20 | Room::tm_boundary = tm_boundary; 21 | } 22 | 23 | RoomBoundary::TriangulatedSurfaceMesh *Room::getTsm_boundary() const { 24 | return tsm_boundary; 25 | } 26 | 27 | void Room::setTsm_boundary(RoomBoundary::TriangulatedSurfaceMesh *tsm_boundary) { 28 | Room::tsm_boundary = tsm_boundary; 29 | } 30 | 31 | RoomBoundary::PolygonMesh *Room::getPm_boundary() const { 32 | return pm_boundary; 33 | } 34 | 35 | void Room::setPm_boundary(RoomBoundary::PolygonMesh *pm_boundary) { 36 | Room::pm_boundary = pm_boundary; 37 | } 38 | 39 | 40 | } -------------------------------------------------------------------------------- /features/Room.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 25. 3 | // 4 | 5 | #ifndef TM2IN_ROOM_H 6 | #define TM2IN_ROOM_H 7 | 8 | #include "features/IndoorComponent.h" 9 | 10 | namespace TM2IN { 11 | /** 12 | * @ingroup geo_features 13 | */ 14 | class Room : public IndoorComponent{ 15 | private: 16 | RoomBoundary::TriangleMesh* tm_boundary; 17 | RoomBoundary::TriangulatedSurfaceMesh* tsm_boundary; 18 | RoomBoundary::PolygonMesh* pm_boundary = NULL; 19 | 20 | public: 21 | /** 22 | * @brief Constructor with TriangleMesh 23 | * 24 | */ 25 | Room(RoomBoundary::TriangleMesh* tm); 26 | 27 | /** 28 | * @brief Returns TriangleMesh boundary 29 | */ 30 | RoomBoundary::TriangleMesh *getTm_boundary() const; 31 | void setTm_boundary(RoomBoundary::TriangleMesh *tm_boundary); 32 | 33 | /** 34 | * @brief Returns TriangulatedSurfaceMesh boundary 35 | */ 36 | RoomBoundary::TriangulatedSurfaceMesh *getTsm_boundary() const; 37 | void setTsm_boundary(RoomBoundary::TriangulatedSurfaceMesh *tsm_boundary); 38 | 39 | /** 40 | * @brief Returns PolygonMesh boundary 41 | */ 42 | RoomBoundary::PolygonMesh *getPm_boundary() const; 43 | void setPm_boundary(RoomBoundary::PolygonMesh *pm_boundary); 44 | 45 | }; 46 | } 47 | 48 | 49 | #endif //TM2IN_ROOM_H 50 | -------------------------------------------------------------------------------- /features/RoomBoundary/PolygonMesh.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 30. 3 | // 4 | 5 | #include "PolygonMesh.h" 6 | 7 | #include "features/Wall/Polygon.h" 8 | #include "TriangleMesh.h" 9 | #include "util.h" 10 | 11 | namespace TM2IN { 12 | namespace RoomBoundary { 13 | void PolygonMesh::tag_ID(string name) { 14 | string type[5] = {"ws" , "fs", "cs", "is", "uk"}; 15 | for (ull i = 0; i < (ull) polygons.size(); i++) { 16 | polygons[i]->geom_id = type[polygons[i]->surface_type] + "_" + to_string(i); 17 | } 18 | } 19 | 20 | TriangleMesh *PolygonMesh::to_triangle_mesh() { 21 | vector triangles; 22 | for (ull i = 0 ; i < polygons.size() ; i++){ 23 | vector p_triangles = polygons[i]->getTriangulation(); 24 | triangles.insert(triangles.end(), p_triangles.begin(), p_triangles.end()); 25 | } 26 | return new TriangleMesh(triangles); 27 | } 28 | 29 | std::string PolygonMesh::asJsonText() { 30 | throw std::runtime_error("PolygonMesh::asJsonText() not implemented"); 31 | } 32 | 33 | void PolygonMesh::updateMBB() { 34 | throw std::runtime_error("PolygonMesh::updateMBB() not implemented"); 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /features/RoomBoundary/PolygonMesh.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 30. 3 | // 4 | 5 | #ifndef TM2IN_POLYGONMESH_H 6 | #define TM2IN_POLYGONMESH_H 7 | 8 | #include 9 | 10 | using namespace std; 11 | using namespace TM2IN::Wall; 12 | 13 | namespace TM2IN { 14 | namespace RoomBoundary { 15 | /** 16 | * @ingroup geo_features 17 | * @brief Mesh consists of only TM2IN::Polygon. 18 | */ 19 | class PolygonMesh : public IndoorComponent { 20 | public: 21 | /** 22 | * @todo encapsulation 23 | */ 24 | vector polygons; 25 | 26 | /** 27 | * @brief Constructor with a Surface vector 28 | */ 29 | PolygonMesh(vector _polygons) : polygons(_polygons) { 30 | this->type=IND_TYPE ::RoomBoundary; 31 | }; 32 | 33 | /** 34 | * @brief Tags ids to polygons 35 | */ 36 | void tag_ID(string name); 37 | 38 | /** 39 | * @brief Convert to TMI2IN::TriangleMesh. 40 | * @warning It process triangulation automatically. 41 | */ 42 | TriangleMesh *to_triangle_mesh(); 43 | 44 | std::string asJsonText() override; 45 | 46 | void updateMBB() override; 47 | private: 48 | }; 49 | } 50 | } 51 | 52 | 53 | #endif //TM2IN_POLYGONMESH_H 54 | -------------------------------------------------------------------------------- /features/RoomBoundary/TriangleMesh.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 25. 3 | // 4 | 5 | #include 6 | #include 7 | #include "util.h" 8 | #include "features/HalfEdge.h" 9 | #include "features/Wall/Triangle.h" 10 | #include "TriangleMesh.h" 11 | 12 | namespace TM2IN{ 13 | namespace RoomBoundary { 14 | TriangleMesh::TriangleMesh(std::vector _triangles) { 15 | this->triangles = _triangles; 16 | this->type=IND_TYPE ::RoomBoundary; 17 | } 18 | 19 | void TriangleMesh::makeGraph() { 20 | std::vector &triangleList = this->triangles; 21 | for (ull i = 0; i < triangleList.size() - 1; i++) { 22 | if (i % 10 == 0) printProcess(i, triangleList.size(), "make Graph"); 23 | for (ull j = i + 1; j < triangleList.size(); j++) { 24 | if (triangleList[i]->checkNeighbor(triangleList[j])) { 25 | if (!triangleList[i]->isOpposite(triangleList[j])) { 26 | } else { 27 | throw std::runtime_error("Opposite Triangle"); 28 | } 29 | } 30 | } 31 | } 32 | return; 33 | } 34 | 35 | bool TriangleMesh::is_closed_triangle_mesh() { 36 | // for (std::map>::iterator it=this->adjMap.begin() ; it != this->adjMap.end(); it++){ 37 | // if (it->second.size() != 3) return false; 38 | // } 39 | return true; 40 | } 41 | 42 | std::vector TriangleMesh::disjoint_meshes() { 43 | std::vector connectedComponent; 44 | std::map checked; 45 | for (int i = 0 ; i < this->triangles.size() ; i++){ 46 | checked[triangles[i]] = false; 47 | } 48 | 49 | for (ull i = 0; i < this->triangles.size(); i++) { 50 | if (!checked[triangles[i]]) { 51 | checked[triangles[i]] = true; 52 | TriangleMesh* tm = this->bfs(this->triangles[i], checked); 53 | connectedComponent.push_back(tm); 54 | } 55 | } 56 | return connectedComponent; 57 | } 58 | 59 | TriangleMesh *TriangleMesh::bfs(Wall::Triangle *&pTriangle, std::map &checked) { 60 | std::vector _triangles; 61 | std::queue wait_queue; 62 | wait_queue.push(pTriangle); 63 | while (wait_queue.size() > 0) { 64 | Wall::Triangle* curr = wait_queue.front(); 65 | wait_queue.pop(); 66 | _triangles.push_back(curr); 67 | 68 | for (unsigned int nb = 0; nb < curr->getVerticesSize(); nb++) { 69 | HalfEdge *pEdge = curr->exterior_boundary_edge(nb)->getOppositeEdge(); 70 | if (pEdge == NULL){ 71 | if (Options::getInstance()->do_validation) 72 | throw std::runtime_error("opposite Edge is NULL in Triangle Mesh bfs"); 73 | else 74 | continue; 75 | } 76 | Wall::Triangle * next_surface = (Wall::Triangle*)(pEdge->parent); 77 | if (next_surface == NULL) throw std::runtime_error("bfs wrong in tm"); 78 | if (checked[next_surface]) continue; 79 | else { 80 | checked[next_surface] = true; 81 | wait_queue.push(next_surface); 82 | } 83 | } 84 | } 85 | TriangleMesh *tm = new TriangleMesh(_triangles); 86 | return tm; 87 | } 88 | 89 | std::vector TriangleMesh::getTriangleList() { 90 | return this->triangles; 91 | } 92 | 93 | void TriangleMesh::updateMBB() { 94 | std::vector cgal_triangles; 95 | for (int i = 0 ; i < this->triangles.size() ; i++){ 96 | cgal_triangles.push_back(this->triangles[i]->CGAL_triangle()); 97 | } 98 | 99 | this->mbb = CGAL::bbox_3(cgal_triangles.begin(), cgal_triangles.end()); 100 | } 101 | 102 | std::string TriangleMesh::asJsonText() { 103 | throw std::runtime_error("TriangleMesh::asJsonText() not implemented"); 104 | } 105 | 106 | std::vector TriangleMesh::extractVerticesList() { 107 | std::vector results; 108 | for (int i = 0 ; i < this->triangles.size() ; i++){ 109 | std::vector triangle_vertices = this->triangles[i]->getVerticesList(); 110 | for (int ti = 0 ; ti < triangle_vertices.size() ; ti++){ 111 | bool found = false; 112 | for (int j = 0 ; j < results.size() ; j++){ 113 | if (triangle_vertices[ti] == results[j]) 114 | found = true; 115 | } 116 | if (!found){ 117 | results.push_back(triangle_vertices[ti]); 118 | } 119 | } 120 | } 121 | return results; 122 | } 123 | } 124 | 125 | } -------------------------------------------------------------------------------- /features/RoomBoundary/TriangleMesh.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 25. 3 | // 4 | 5 | #ifndef TM2IN_TRIANGLEMESH_H 6 | #define TM2IN_TRIANGLEMESH_H 7 | 8 | #include 9 | 10 | using namespace TM2IN::Wall; 11 | 12 | namespace TM2IN{ 13 | namespace RoomBoundary{ 14 | /** 15 | * @ingroup geo_features 16 | * @brief Mesh consists of only TM2IN::Triangle 17 | */ 18 | class TriangleMesh : public IndoorComponent { 19 | private: 20 | /** 21 | * @todo encapsulation 22 | */ 23 | std::vector triangles; 24 | TriangleMesh *bfs(Triangle *&pTriangle, std::map &checked); 25 | public: 26 | /** 27 | * @brief Constructor with a Triangle vector. 28 | */ 29 | TriangleMesh(std::vector _triangles); 30 | /** 31 | * @brief Makes Graph 32 | * @todo be removed 33 | */ 34 | void makeGraph(); 35 | /** 36 | * 37 | * @brief Checks mesh is closed 38 | */ 39 | bool is_closed_triangle_mesh(); 40 | 41 | /** 42 | * @brief Disjoint one mesh to multiple meshes by using connected component. 43 | */ 44 | std::vector disjoint_meshes(); 45 | 46 | /** 47 | * @brief Gets a list of all Triangle in mesh. 48 | * 49 | */ 50 | std::vector getTriangleList(); 51 | 52 | /** 53 | * @brief Gets a set of all Vertices in mesh. 54 | * 55 | */ 56 | std::vector extractVerticesList(); 57 | 58 | std::string asJsonText() override; 59 | 60 | void updateMBB() override; 61 | }; 62 | } 63 | } 64 | 65 | 66 | #endif //TM2IN_TRIANGLEMESH_H 67 | -------------------------------------------------------------------------------- /features/RoomBoundary/TriangulatedSurfaceMesh.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 30. 3 | // 4 | 5 | #include "util.h" 6 | #include "TriangleMesh.h" 7 | 8 | #include "TriangulatedSurfaceMesh.h" 9 | #include "features/Wall/TriangulatedSurface.h" 10 | #include "features/HalfEdge.h" 11 | #include 12 | #include 13 | #include 14 | 15 | using namespace std; 16 | 17 | namespace TM2IN{ 18 | namespace RoomBoundary{ 19 | TriangulatedSurfaceMesh::TriangulatedSurfaceMesh(TM2IN::RoomBoundary::TriangleMesh *tm) { 20 | vector triangles = tm->getTriangleList(); 21 | ull size = triangles.size(); 22 | for (ull i = 0; i < size; i++) { 23 | Wall::TriangulatedSurface* newcp = new Wall::TriangulatedSurface(*triangles[i]); 24 | surfaces.push_back(newcp); 25 | } 26 | this->type=IND_TYPE ::RoomBoundary; 27 | } 28 | 29 | void TriangulatedSurfaceMesh::setSurfacesList(vector s_list) { 30 | this->surfaces = s_list; 31 | } 32 | 33 | vector TriangulatedSurfaceMesh::surface_list() { 34 | return this->surfaces; 35 | } 36 | 37 | int TriangulatedSurfaceMesh::surface_easy_validation() { 38 | cout << "\n------------- check whether surfaces are valid (easy) --------------\n" << endl; 39 | for (vector::size_type i = 0; i < this->surfaces.size();) { 40 | Wall::TriangulatedSurface * pSurface = this->surfaces[i]; 41 | pSurface->updateMBB(); 42 | 43 | if (pSurface->easy_validation()) { 44 | i++; 45 | } else { 46 | cerr << pSurface->asJsonText() << endl; 47 | return -1; 48 | } 49 | } 50 | return 0; 51 | } 52 | 53 | int TriangulatedSurfaceMesh::update_surfaces_normal() { 54 | cout << "\n------------updateNormal------------\n" << endl; 55 | for (ull i = 0; i < (int) this->surfaces.size(); i++) { 56 | Wall::TriangulatedSurface* surface = this->surfaces[i]; 57 | if (!surface->updateNormal()) { 58 | cout << surface->asJsonText() << endl; 59 | cout << "Cannot make Normal" << endl; 60 | exit(-1); 61 | } 62 | 63 | } 64 | return 0; 65 | } 66 | 67 | ull TriangulatedSurfaceMesh::num_of_surfaces() { 68 | return (ull)this->surfaces.size(); 69 | } 70 | 71 | bool TriangulatedSurfaceMesh::isClosed() { 72 | map checked; 73 | for (TriangulatedSurface *sf : this->surfaces) 74 | checked[sf] = false; 75 | 76 | std::queue wait_queue; 77 | wait_queue.push(this->surfaces[0]); 78 | checked[this->surfaces[0]] = true; 79 | 80 | int surfaceCount = 0; 81 | 82 | while (wait_queue.size() > 0) { 83 | Wall::TriangulatedSurface * current = wait_queue.front(); 84 | wait_queue.pop(); 85 | 86 | surfaceCount += 1; 87 | for (unsigned int nb = 0; nb < current->getVerticesSize(); nb++) { 88 | Wall::TriangulatedSurface* next_surface = (Wall::TriangulatedSurface*)current->exterior_boundary_edge(nb)->getOppositeEdge()->parent; 89 | if (checked[next_surface]) continue; 90 | else { 91 | checked[next_surface] = true; 92 | wait_queue.push(next_surface); 93 | } 94 | } 95 | } 96 | 97 | if (surfaceCount != this->surfaces.size()) { 98 | return false; 99 | } else 100 | return true; 101 | } 102 | 103 | int TriangulatedSurfaceMesh::surface_strict_validation() { 104 | cout << "\n------------- check whether surfaces are valid --------------\n" << endl; 105 | for (vector::size_type i = 0; i < this->surfaces.size();) { 106 | Wall::TriangulatedSurface * pSurface = this->surfaces[i]; 107 | pSurface->updateMBB(); 108 | 109 | if (pSurface->strict_validation()) { 110 | i++; 111 | } else { 112 | cerr << pSurface->asJsonText() << endl; 113 | return -1; 114 | } 115 | } 116 | return 0; 117 | } 118 | 119 | std::string TriangulatedSurfaceMesh::asJsonText() { 120 | throw std::runtime_error("TriangulatedSurfaceMesh::asJsonText() not implemented"); 121 | } 122 | 123 | void TriangulatedSurfaceMesh::updateMBB() { 124 | throw std::runtime_error("TriangulatedSurfaceMesh::updateMBB not implemented"); 125 | } 126 | 127 | void TriangulatedSurfaceMesh::classify_sf_type() { 128 | vector normal_list = { 129 | Vector_3(0,0,-1), // cs 130 | Vector_3(0,0,1), // fs 131 | Vector_3(1,0,0), // ws 132 | Vector_3(0,1,0), 133 | Vector_3(-1,0,0), 134 | Vector_3(0,-1,0), 135 | Vector_3(1,1,0), 136 | Vector_3(1,-1,0), 137 | Vector_3(-1,-1,0), 138 | Vector_3(-1,1,0) 139 | }; 140 | 141 | for (vector::size_type i = 0; i < this->surfaces.size(); i++) { 142 | Wall::TriangulatedSurface * pSurface = this->surfaces[i]; 143 | Vector_3 nv = pSurface->normal; 144 | int type = TM2IN::detail::cgal::find_closest_vector(nv, normal_list); 145 | if (type == 0){ 146 | pSurface->surface_type = SURFACE_TYPE::CS; 147 | } 148 | else if (type == 1){ 149 | pSurface->surface_type = SURFACE_TYPE::FS; 150 | } 151 | else{ 152 | pSurface->surface_type = SURFACE_TYPE::WS; 153 | } 154 | 155 | } 156 | } 157 | 158 | 159 | } 160 | } 161 | 162 | -------------------------------------------------------------------------------- /features/RoomBoundary/TriangulatedSurfaceMesh.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 30. 3 | // 4 | 5 | #ifndef TM2IN_TRIANGULATEDSURFACEMESH_H 6 | #define TM2IN_TRIANGULATEDSURFACEMESH_H 7 | 8 | #include 9 | #include "util.h" 10 | 11 | using namespace TM2IN::Wall; 12 | 13 | namespace TM2IN { 14 | namespace RoomBoundary { 15 | /** 16 | * @ingroup geo_features 17 | * Mesh consists of only TM2IN::TriangulatedSurface. 18 | */ 19 | class TriangulatedSurfaceMesh : public IndoorComponent{ 20 | public: 21 | /** 22 | * @brief Constructor with a TriangleMesh 23 | * 24 | */ 25 | TriangulatedSurfaceMesh(TriangleMesh* tm); 26 | 27 | /** 28 | * @brief Gets a list of all Surface. 29 | * 30 | */ 31 | std::vector surface_list(); 32 | 33 | /** 34 | * @brief Sets a list of Surface to patches. 35 | * 36 | */ 37 | void setSurfacesList(std::vector vector); 38 | 39 | /** 40 | * @brief Surface 41 | * @todo encapsulate 42 | */ 43 | std::vector surfaces; 44 | 45 | /** 46 | * @brief Validate with easy restriction 47 | */ 48 | int surface_easy_validation(); 49 | 50 | /** 51 | * @brief Validate with strict restriction 52 | */ 53 | int surface_strict_validation(); 54 | 55 | /** 56 | * @brief Updates normal vectors of all patches 57 | */ 58 | int update_surfaces_normal(); 59 | 60 | /** 61 | * @brief Gets the number of patches in the mesh. 62 | */ 63 | ull num_of_surfaces(); 64 | 65 | /** 66 | * @brief Checks this is closed. 67 | */ 68 | bool isClosed(); 69 | 70 | std::string asJsonText() override; 71 | 72 | void updateMBB() override; 73 | 74 | /** 75 | * @brief classify Surfaces with SURFACE_TYPE 76 | */ 77 | void classify_sf_type(); 78 | private: 79 | 80 | }; 81 | typedef TM2IN::RoomBoundary::TriangulatedSurfaceMesh TSM; 82 | } 83 | } 84 | 85 | 86 | #endif //TM2IN_TRIANGULATEDSURFACEMESH_H 87 | -------------------------------------------------------------------------------- /features/Vertex.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "features/Vertex.h" 5 | #include "detail/io/JsonWriter.h" 6 | 7 | using namespace std; 8 | 9 | namespace TM2IN { 10 | std::string Vertex::asJsonText() { 11 | return TM2IN::detail::io::vertex_to_json(*this, this->geom_id); 12 | } 13 | 14 | void Vertex::translate(double diff[]) { 15 | for (int i = 0; i < 3; i++) coords[i] += diff[i]; 16 | } 17 | 18 | void Vertex::translateTo(vector dest) { 19 | for (int i = 0; i < 3; i++) coords[i] = dest[i]; 20 | } 21 | 22 | 23 | Kernel::Point_3 Vertex::CGAL_point() { 24 | return TM2IN::detail::cgal::to_CGAL_Point_3(*this); 25 | } 26 | 27 | void Vertex::setCoords(double x, double y, double z) { 28 | coords[0] = x; 29 | coords[1] = y; 30 | coords[2] = z; 31 | } 32 | 33 | std::ostream &operator<<(std::ostream &ou, Vertex *pVertex) { 34 | ou << pVertex->asJsonText() << std::endl; 35 | return ou; 36 | } 37 | 38 | std::string Vertex::asWKT() { 39 | return TM2IN::detail::io::vertex_to_wkt(this); 40 | } 41 | } -------------------------------------------------------------------------------- /features/Vertex.h: -------------------------------------------------------------------------------- 1 | #ifndef VERTEX_H_INCLUDED 2 | #define VERTEX_H_INCLUDED 3 | 4 | #include 5 | 6 | #include "util.h" 7 | #include "detail/cgal_config.h" 8 | #include "IndoorComponent.h" 9 | 10 | namespace TM2IN { 11 | /** 12 | * @ingroup geo_features 13 | * @brief Vertex imply one coordinate in 3-D indoor space. 14 | */ 15 | class Vertex : public IndoorComponent { 16 | public: 17 | double coords[3]; 18 | 19 | /** 20 | * @brief Empty Vertex constructor 21 | */ 22 | Vertex() : Vertex(0, 0, 0) {} 23 | 24 | /** 25 | * @brief Constructor with three double values 26 | */ 27 | Vertex(double px, double py, double pz) { 28 | coords[0] = CGAL::to_double(px); 29 | coords[1] = CGAL::to_double(py); 30 | coords[2] = CGAL::to_double(pz); 31 | type = TM2IN::IND_TYPE::Vertex; 32 | } 33 | 34 | /** 35 | * @brief Copy constructor. 36 | */ 37 | Vertex(Vertex &vt) : Vertex(vt.x(), vt.y(), vt.z()) { } 38 | 39 | /** 40 | * @brief Destructor 41 | */ 42 | ~Vertex() {} 43 | 44 | /** 45 | * @brief Gets x value. 46 | */ 47 | double x() { return coords[0]; } 48 | 49 | /** 50 | * @brief Gets y value 51 | */ 52 | double y() { return coords[1]; } 53 | 54 | /** 55 | * @brief Gets z value 56 | */ 57 | double z() { return coords[2]; } 58 | 59 | /** 60 | * @brief Sets x value 61 | * 62 | */ 63 | void setX(double value) { coords[0] = value; } 64 | 65 | /** 66 | * @brief Sets y value 67 | */ 68 | void setY(double value) { coords[1] = value; } 69 | 70 | /** 71 | * @brief Sets z value 72 | */ 73 | void setZ(double value) { coords[2] = value; } 74 | 75 | /** 76 | * @brief Sets coordinate with three float values. 77 | */ 78 | void setCoords(double x, double y, double z); 79 | 80 | /** 81 | * @brief Operator [] to access each value 82 | */ 83 | double operator[](int idx) { 84 | return coords[idx]; 85 | } 86 | 87 | /** 88 | * @brief Translate coordinate values with difference 89 | */ 90 | void translate(double diff[]); 91 | 92 | /** 93 | * @brief Move Vertex to destination 94 | */ 95 | void translateTo(std::vector dest); 96 | 97 | std::string asJsonText(); 98 | std::string asWKT(); 99 | 100 | 101 | /** 102 | * @brief Operator << : print string 103 | */ 104 | friend std::ostream &operator<<(std::ostream &ou, Vertex *pVertex); 105 | 106 | /** 107 | * @brief Converts to Kernel::Point_3 108 | */ 109 | Kernel::Point_3 CGAL_point(); 110 | }; 111 | 112 | 113 | /** < for Searching upper_bound and lower_bound */ 114 | struct CompareVertex_X 115 | { 116 | bool operator()( const Vertex* v, double x ) const 117 | { 118 | return v->coords[0] < x; 119 | } 120 | 121 | bool operator()( const Vertex* v1, const Vertex* v2 ) const 122 | { 123 | return v1->coords[0] < v2->coords[0]; 124 | } 125 | 126 | bool operator()( double time1, double time2 ) const 127 | { 128 | return time1 < time2; 129 | } 130 | 131 | bool operator()( double time, const Vertex* v ) const 132 | { 133 | return time < v->coords[0]; 134 | } 135 | }; 136 | } 137 | 138 | 139 | #endif // VERTEX_H_INCLUDED 140 | -------------------------------------------------------------------------------- /features/Wall/Polygon.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 8. 13. 3 | // 4 | 5 | #include "Polygon.h" 6 | #include "features/HalfEdge.h" 7 | 8 | namespace TM2IN { 9 | namespace Wall { 10 | 11 | bool Polygon::updateNormal() { 12 | return false; 13 | } 14 | 15 | Polygon::Polygon(Surface * pSurface) { 16 | this->exteriorBoundary = pSurface->getExteriorBoundary(); 17 | this->normal = pSurface->normal; 18 | // this->mbb = new MinimumBoundingBox(pSurface->getMBB()); 19 | this->mbb = pSurface->getMBB(); 20 | this->area = pSurface->getArea(); 21 | this->geom_id = pSurface->geom_id; 22 | this->type = TM2IN::IND_TYPE::Polygon; 23 | this->surface_type = pSurface->surface_type; 24 | if (!is_valid_polygon()){ 25 | throw std::runtime_error("This Surface cannot be polygon.."); 26 | } 27 | } 28 | 29 | 30 | /** 31 | * @todo impl 32 | * @return 33 | */ 34 | bool Polygon::is_valid_polygon(){ 35 | return true; 36 | } 37 | 38 | Polygon::Polygon(vector vt_list) { 39 | for (ull index = 0 ; index < vt_list.size() - 1 ; index++ ){ 40 | exteriorBoundary.push_back(new HalfEdge(vt_list[index], vt_list[index + 1], this)); 41 | } 42 | exteriorBoundary.push_back(new HalfEdge(vt_list[vt_list.size() - 1], vt_list[0], this)); 43 | this->area = 0.0; 44 | this->updateMBB(); 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /features/Wall/Polygon.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 8. 13. 3 | // 4 | 5 | #ifndef TM2IN_POLYGON_H 6 | #define TM2IN_POLYGON_H 7 | 8 | #include "Surface.h" 9 | 10 | namespace TM2IN { 11 | namespace Wall { 12 | /** 13 | * @ingroup geo_features 14 | * @brief Surface with planar edges and vertices. 15 | */ 16 | class Polygon : public Surface{ 17 | public: 18 | Polygon(Surface* ); 19 | 20 | Polygon(vector vt_list); 21 | 22 | /** 23 | * @brief Checks this polygon is valid. 24 | * @todo imp 25 | */ 26 | bool is_valid_polygon(); 27 | 28 | bool updateNormal() override; 29 | }; 30 | } 31 | } 32 | 33 | 34 | #endif //TM2IN_POLYGON_H 35 | -------------------------------------------------------------------------------- /features/Wall/Surface.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 8. 9. 3 | // 4 | 5 | #include 6 | #include "algorithm/triangulation.h" 7 | #include "algorithm/compare.h" 8 | #include "detail/features/halfedge_string.h" 9 | #include "detail/io/JsonWriter.h" 10 | #include "detail/algorithm/self_intersect.h" 11 | #include "features/HalfEdge.h" 12 | #include "features/Vertex.h" 13 | #include "Surface.h" 14 | 15 | namespace TM2IN { 16 | namespace Wall { 17 | void Surface::setVertex(int index, Vertex *vt) { 18 | this->exteriorBoundary[index]->setVertex(0, vt); 19 | if (index == 0) 20 | this->exteriorBoundary[this->getVerticesSize() - 1]->setVertex(1, vt); 21 | else 22 | this->exteriorBoundary[index - 1]->setVertex(1, vt); 23 | } 24 | 25 | void Surface::insertVertex(int index, Vertex *vt) { 26 | // this->v_list.insert(this->v_list.begin() + index, vt); 27 | cerr << "TODO : insertVertex" << endl; 28 | } 29 | 30 | Vertex *Surface::vertex(int index) { 31 | return this->exteriorBoundary[index]->vertices[0]; 32 | } 33 | 34 | Vector_3 Surface::getNormal() 35 | { 36 | return this->normal; 37 | } 38 | 39 | std::ostream& operator<<(std::ostream &ou, Surface *pSurface) { 40 | ou << pSurface->asJsonText() << endl; 41 | return ou; 42 | } 43 | 44 | vector Surface::getVerticesList() { 45 | return TM2IN::detail::HalfEdgeString::getFirstVertexList(this->exteriorBoundary); 46 | } 47 | 48 | void Surface::setVertexList(std::vector newVertices) { 49 | this->exteriorBoundary.clear(); 50 | for (int i = 0 ; i < newVertices.size() - 1; i++){ 51 | TM2IN::Vertex* v1 = newVertices[i]; 52 | TM2IN::Vertex* v2 = newVertices[i+1]; 53 | this->exteriorBoundary.push_back(new HalfEdge(v1, v2, this)); 54 | } 55 | this->exteriorBoundary.push_back(new HalfEdge(newVertices[newVertices.size() - 1], newVertices[0], this)); 56 | } 57 | 58 | std::vector Surface::getExteriorBoundary() { 59 | if (exteriorBoundary.size() == 0) cerr << "no boundary" << endl; 60 | return exteriorBoundary; 61 | } 62 | 63 | void Surface::setExteriorBoundary(std::vector edges){ 64 | this->exteriorBoundary.clear(); 65 | this->exteriorBoundary = edges; 66 | } 67 | 68 | HalfEdge *Surface::exterior_boundary_edge(int i) { 69 | return this->exteriorBoundary[i]; 70 | } 71 | 72 | int Surface::index_of_exterior_boundary_edge(HalfEdge *pEdge) { 73 | int i = 0; 74 | for (HalfEdge* he : this->exteriorBoundary){ 75 | if (pEdge == he) return i; 76 | i++; 77 | } 78 | return -1; 79 | } 80 | 81 | bool Surface::has_duplicate_vertex(){ 82 | vector sorted_v_list(this->getVerticesList()); 83 | sort(sorted_v_list.begin(), sorted_v_list.end(), TM2IN::algorithm::greater); 84 | for (ull i = 0 ; i < sorted_v_list.size() - 1; i++){ 85 | if (sorted_v_list[i] == sorted_v_list[i+1]){ 86 | return true; 87 | } 88 | } 89 | return false; 90 | } 91 | 92 | bool Surface::is_simple(){ 93 | if (has_duplicate_vertex()) return false; 94 | return !TM2IN::detail::algorithm::has_self_intersection(this->getExteriorBoundary()); 95 | } 96 | 97 | int Surface::getSegmentsNumber(ll si, ll ei) { 98 | if (si >= this->getVerticesSize() || ei >= getVerticesSize()){ 99 | cerr << "getSegmentsNumber Error" << endl; 100 | return -1; 101 | } 102 | if (ei >= si){ 103 | return ei - si; 104 | } 105 | else{ 106 | return this->getVerticesSize() - si + ei; 107 | } 108 | } 109 | 110 | void Surface::updateMBB() { 111 | double max_coords[3] = {0}; 112 | double min_coords[3] = {0}; 113 | for (int i = 0 ; i < 3 ; i++) 114 | { 115 | max_coords[i] = -10000000.000; 116 | min_coords[i] = 10000000.00; 117 | } 118 | 119 | for (unsigned int i = 0 ; i < this->getVerticesSize() ; i++){ 120 | for (int j = 0 ; j < 3 ; j++){ 121 | max_coords[j] = max(max_coords[j], this->vertex(i)->coords[j]); 122 | min_coords[j] = min(min_coords[j], this->vertex(i)->coords[j]); 123 | } 124 | } 125 | // this->mbb->set_min_coords(min_coords); 126 | // this->mbb->set_max_coords(max_coords); 127 | this->mbb = TM2IN::detail::cgal::create_bbox3(min_coords, max_coords); 128 | } 129 | 130 | std::vector Surface::getTriangulation(){ 131 | if (this->triangulation.size() == 0) { 132 | vector triList; 133 | TM2IN::algorithm::triangulate(this, triList); 134 | this->triangulation = triList; 135 | } 136 | return this->triangulation; 137 | } 138 | 139 | bool Surface::compareLength(Surface* i, Surface* j) { 140 | return (i->getVerticesSize() > j->getVerticesSize()); 141 | } 142 | 143 | bool Surface::isOpposite(Surface* sf){ 144 | for (ll i = 0 ; i < (ll) sf->getVerticesSize() ; i++){ 145 | if (this->vertex(0) == sf->vertex(i)){ 146 | ll sf_index = i + 1; 147 | if (sf_index == (ll) sf->getVerticesSize()) sf_index = 0; 148 | ll this_index = this->getVerticesSize() - 1; 149 | while (this->vertex(this_index) == sf->vertex(sf_index)){ 150 | this_index--; sf_index++; 151 | if (sf_index == (ll) sf->getVerticesSize()) sf_index = 0; 152 | if (this_index == 0 || sf_index == i) break; 153 | 154 | } 155 | if (this->vertex(this_index) != sf->vertex(sf_index)) 156 | return false; 157 | else 158 | return true; 159 | 160 | } 161 | } 162 | return false; 163 | } 164 | 165 | std::string Surface::asJsonText(){ 166 | return TM2IN::detail::io::surface_to_json(*this); 167 | } 168 | 169 | 170 | 171 | } 172 | } -------------------------------------------------------------------------------- /features/Wall/Surface.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 8. 7. 3 | // 4 | 5 | #ifndef TM2IN_WALL_SURFACE_H 6 | #define TM2IN_WALL_SURFACE_H 7 | 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | namespace TM2IN{ 14 | namespace Wall{ 15 | enum SURFACE_TYPE {WS, FS, CS, IS, UNKNOWN}; 16 | 17 | /** 18 | * @ingroup geo_features 19 | */ 20 | class Surface : public IndoorComponent{ 21 | private: 22 | protected: 23 | /** 24 | * @brief Empty Surface constructor 25 | */ 26 | Surface(){} 27 | 28 | std::vector innerEdges; 29 | std::vector exteriorBoundary; 30 | 31 | std::vector triangulation; 32 | 33 | int neighbors = 0; 34 | public: 35 | Vector_3 normal = CGAL::NULL_VECTOR; 36 | 37 | int surface_type = SURFACE_TYPE::UNKNOWN; 38 | 39 | /** 40 | * @brief Gets the size of Vertex list 41 | */ 42 | ull getVerticesSize(){ return exteriorBoundary.size(); } 43 | 44 | /** 45 | * @brief Set specific Vertex with index 46 | */ 47 | virtual void setVertex(int index, Vertex* vt); 48 | /** 49 | * @brief Read Vertex with index 50 | */ 51 | virtual Vertex* vertex(int index); 52 | 53 | /** 54 | * @brief Insert Vertex with index 55 | * @todo implements 56 | */ 57 | void insertVertex(int index, Vertex* vt); 58 | 59 | /** 60 | * @brief Set normal vector 61 | */ 62 | void setNormal(Vector_3 _normal){ this->normal = _normal; } 63 | 64 | /** 65 | * @brief Gets normal vector 66 | */ 67 | Vector_3 getNormal(); 68 | 69 | /** 70 | * @brief ostream operator 71 | */ 72 | friend std::ostream& operator<<(std::ostream& ou, Surface* pSurface); 73 | 74 | /** 75 | * @brief Gets a list of all Vertex 76 | */ 77 | std::vector getVerticesList(); 78 | 79 | /** 80 | * @brief Sets Vertex list 81 | */ 82 | void setVertexList(std::vector vertices); 83 | 84 | /** 85 | * @brief Gets a exterior boundary 86 | */ 87 | std::vector getExteriorBoundary(); 88 | 89 | /** 90 | * @brief Sets a exterior boundary with a vector of HalfEdge 91 | */ 92 | void setExteriorBoundary(std::vector edges); 93 | 94 | /** 95 | * @brief Returns the i-th edge. 96 | */ 97 | HalfEdge *exterior_boundary_edge(int i); 98 | 99 | /** 100 | * @brief Returns the index of pEdge 101 | */ 102 | int index_of_exterior_boundary_edge(HalfEdge *pEdge); 103 | 104 | /** 105 | * @brief Checks Surface has duplicate vertex 106 | */ 107 | bool has_duplicate_vertex(); 108 | 109 | /** 110 | * @brief Checks Surface is simple 111 | */ 112 | bool is_simple(); 113 | 114 | /** 115 | * @brief Gets the number of edges between start index and end index. 116 | */ 117 | int getSegmentsNumber(ll start_index, ll end_index); 118 | 119 | 120 | /** 121 | * @brief Compares with Surface length 122 | */ 123 | static bool compareLength(Surface* i, Surface* j); 124 | 125 | /** 126 | * @brief 127 | */ 128 | bool isOpposite(Surface* sf); 129 | 130 | /** 131 | * @brief 132 | */ 133 | void updateMBB(); 134 | 135 | /** 136 | * @brief Triangulate Surface. 137 | */ 138 | std::vector getTriangulation(); 139 | 140 | /** 141 | * @brief Updates normal vector 142 | */ 143 | virtual bool updateNormal() = 0; 144 | /** 145 | * @brief 146 | */ 147 | std::string asJsonText(); 148 | 149 | int getNeighborNumber(){ 150 | return neighbors; 151 | } 152 | 153 | }; 154 | } 155 | } 156 | 157 | #endif //TM2IN_WALL_SURFACE_H 158 | -------------------------------------------------------------------------------- /features/Wall/Triangle.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 8. 9. 3 | // 4 | 5 | #define MIN_TRIANGLE_AREA 0.0000001 6 | 7 | #include 8 | #include "Triangle.h" 9 | 10 | #include "detail/cgal/type_conversion.h" 11 | #include "features/HalfEdge.h" 12 | #include "cgal/triangle.h" 13 | 14 | namespace TM2IN { 15 | namespace Wall { 16 | Triangle::Triangle(Vertex *pa, Vertex *pb, Vertex *pc) { 17 | this->type = IND_TYPE::Triangle; 18 | 19 | exteriorBoundary.push_back(new HalfEdge(pa, pb, this)); 20 | exteriorBoundary.push_back(new HalfEdge(pb, pc, this)); 21 | exteriorBoundary.push_back(new HalfEdge(pc, pa, this)); 22 | Vector_3 _normal = cgal::triangle_normal(pa, pb, pc); 23 | this->area = CGAL::to_double(sqrt(_normal.squared_length())) / 2; 24 | if (this->area != 0.0 && this->area == this->area) 25 | this->normal = _normal; 26 | else { 27 | if (Options::getInstance()->do_validation) 28 | throw std::runtime_error("create Triangle Error!!"); 29 | else{ 30 | this->normal = _normal; 31 | this->area = MIN_TRIANGLE_AREA; 32 | } 33 | } 34 | this->updateMBB(); 35 | } 36 | 37 | 38 | bool Triangle::setNeighbor(Triangle *&tri, int i, int j) { 39 | if (i != -1 && j !=-1){ 40 | if (this->exteriorBoundary[i]->can_be_opposite_edge(tri->exteriorBoundary[j])) { 41 | assert(this->exteriorBoundary[i]->getOppositeEdge() == NULL); 42 | assert(tri->exteriorBoundary[j]->getOppositeEdge() == NULL); 43 | this->exteriorBoundary[i]->setOppositeEdge(tri->exteriorBoundary[j]); 44 | tri->exteriorBoundary[j]->setOppositeEdge(this->exteriorBoundary[i]); 45 | this->neighbors++; 46 | tri->neighbors++; 47 | return true; 48 | } 49 | return false; 50 | } 51 | 52 | bool isAdjacent = false; 53 | for (int v1 = 0; v1 < 3; v1++) { 54 | for (int v2 = 0; v2 < 3; v2++) { 55 | if (this->exteriorBoundary[v1]->can_be_opposite_edge(tri->exteriorBoundary[v2])) { 56 | isAdjacent = true; 57 | assert(this->exteriorBoundary[v1]->getOppositeEdge() == NULL); 58 | assert(tri->exteriorBoundary[v2]->getOppositeEdge() == NULL); 59 | this->exteriorBoundary[v1]->setOppositeEdge(tri->exteriorBoundary[v2]); 60 | tri->exteriorBoundary[v2]->setOppositeEdge(this->exteriorBoundary[v1]); 61 | this->neighbors++; 62 | tri->neighbors++; 63 | } 64 | } 65 | } 66 | return isAdjacent; 67 | } 68 | 69 | 70 | Kernel::Triangle_3 Triangle::CGAL_triangle() { 71 | return TM2IN::detail::cgal::to_CGAL_Triangle_3(*this); 72 | } 73 | 74 | bool Triangle::checkNeighbor(Triangle *&tri) { 75 | for (int v1 = 0; v1 < 3; v1++) { 76 | if (this->exteriorBoundary[v1]->oppositeEdge != NULL && 77 | this->exteriorBoundary[v1]->oppositeEdge->parent == tri) { 78 | return true; 79 | } 80 | } 81 | return false; 82 | } 83 | 84 | bool Triangle::isOpposite(Triangle *tri) { 85 | int num_of_opposite = 0; 86 | for (int i = 0; i < 3; i++) { 87 | if (this->exterior_boundary_edge(i)->getOppositeEdge() != NULL && 88 | this->exterior_boundary_edge(i)->oppositeEdge->parent == tri) { 89 | num_of_opposite++; 90 | } 91 | if (num_of_opposite == 2) { 92 | std::cerr << "isOpposite worognonrownr" << std::endl; 93 | exit(-1); 94 | } 95 | } 96 | return num_of_opposite == 3; 97 | 98 | } 99 | 100 | bool Triangle::updateNormal() { 101 | this->normal = TM2IN::cgal::triangle_normal(vertex(0), vertex(1), vertex(2)); 102 | return true; 103 | } 104 | } 105 | } -------------------------------------------------------------------------------- /features/Wall/Triangle.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 8. 9. 3 | // 4 | 5 | #ifndef TM2IN_WALL_TRIANGLE_H 6 | #define TM2IN_WALL_TRIANGLE_H 7 | 8 | #include "features/IndoorComponent.h" 9 | #include "Surface.h" 10 | 11 | namespace TM2IN { 12 | namespace Wall { 13 | /** 14 | * @ingroup geo_features 15 | * @brief Wall with three edges (HalfEdge) and vertices (Vertex) 16 | */ 17 | class Triangle : public Surface{ 18 | public: 19 | /** 20 | * @brief Constructor with three Vertex 21 | * 22 | */ 23 | Triangle(Vertex *pa, Vertex *pb, Vertex *pc); 24 | 25 | /** 26 | * @brief Constructor with a Vertex vector 27 | * @warning The only front three vertices in vector will be used. 28 | */ 29 | Triangle(std::vector &vertices) : Triangle(vertices[0], vertices[1], vertices[2]) {} 30 | 31 | 32 | /** 33 | * @brief Sets neighbor relationship if Triangle has opposite HalfEdge 34 | * 35 | */ 36 | bool setNeighbor(Triangle *&tri, int i = -1, int j = -1); 37 | 38 | /** 39 | * @brief Converts to Kernel::Triangle_3 40 | */ 41 | Kernel::Triangle_3 CGAL_triangle(); 42 | 43 | /** 44 | * @brief Checks the other triangle has opposite HalfEdge 45 | */ 46 | bool checkNeighbor(Triangle *&tri); 47 | /** 48 | * @brief Checks the other Triangle has three opposite HalfEdge 49 | */ 50 | bool isOpposite(Triangle *tri); 51 | 52 | bool updateNormal() override; 53 | 54 | }; 55 | } 56 | } 57 | 58 | 59 | #endif //TM2IN_WALL_TRIANGLE_H 60 | -------------------------------------------------------------------------------- /features/Wall/TriangulatedSurface.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 8. 9. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "features/Wall/Triangle.h" 10 | #include "cgal/triangle.h" 11 | #include "TriangulatedSurface.h" 12 | 13 | namespace TM2IN { 14 | namespace Wall { 15 | TriangulatedSurface::TriangulatedSurface() { 16 | type = TM2IN::IND_TYPE::TriangulatedSurface; 17 | } 18 | 19 | TriangulatedSurface::TriangulatedSurface(TriangulatedSurface *pSurface) { 20 | this->exteriorBoundary = pSurface->getExteriorBoundary(); 21 | TM2IN::detail::HalfEdgeString::setParent(this->exteriorBoundary, this); 22 | this->normal = pSurface->normal; 23 | //this->mbb = new MinimumBoundingBox(pSurface->getMBB()); 24 | this->mbb = pSurface->getMBB(); 25 | this->area = pSurface->getArea(); 26 | this->triangles = pSurface->triangles; 27 | this->geom_id = pSurface->geom_id; 28 | this->type = TM2IN::IND_TYPE::TriangulatedSurface; 29 | this->surface_type = pSurface->surface_type; 30 | } 31 | 32 | TriangulatedSurface::TriangulatedSurface(Triangle& pl){ 33 | this->geom_id = "sf" + pl.geom_id; 34 | this->exteriorBoundary = pl.getExteriorBoundary(); 35 | TM2IN::detail::HalfEdgeString::setParent(this->exteriorBoundary, this); 36 | 37 | area = pl.getArea(); 38 | normal = pl.getNormal(); 39 | 40 | // this->updateMBB(); 41 | this->mbb = pl.getMBB(); 42 | this->triangles.push_back(&pl); 43 | this->type = TM2IN::IND_TYPE::TriangulatedSurface; 44 | this->surface_type = pl.surface_type; 45 | } 46 | 47 | bool TriangulatedSurface::strict_validation(){ 48 | if (!easy_validation()) { 49 | return false; 50 | } 51 | return this->is_simple(); 52 | } 53 | 54 | bool TriangulatedSurface::easy_validation(){ 55 | if (this->getVerticesSize() < 3) { 56 | return false; 57 | } 58 | return !this->has_duplicate_vertex(); 59 | } 60 | 61 | bool TriangulatedSurface::updateNormal() { 62 | if (this->getVerticesSize() <= 4){ 63 | Vector_3 normal = Vector_3(0,0,0); 64 | for (int i = 0 ; i < (int) this->getVerticesSize() - 1 ; i += 2){ 65 | int e_i = i + 2 >= (int) this->getVerticesSize()? 0 : i+2; 66 | normal = normal + TM2IN::cgal::triangle_normal(vertex(i), vertex(i + 1), vertex(e_i)); 67 | } 68 | this->normal = normal; 69 | } 70 | if (Options::getInstance()->do_validation) 71 | assert(this->normal != CGAL::NULL_VECTOR); 72 | 73 | return true; 74 | } 75 | 76 | std::vector TriangulatedSurface::getNeighborList() { 77 | std::vector neighbors; 78 | for (HalfEdge* he : this->exteriorBoundary){ 79 | if (he->oppositeEdge != NULL && he->oppositeEdge->parent != NULL) 80 | neighbors.push_back((Wall::TriangulatedSurface *)he->oppositeEdge->parent); 81 | } 82 | return neighbors; 83 | } 84 | } 85 | } -------------------------------------------------------------------------------- /features/Wall/TriangulatedSurface.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 8. 9. 3 | // 4 | 5 | #ifndef TM2IN_TRIANGULATEDSURFACE_H 6 | #define TM2IN_TRIANGULATEDSURFACE_H 7 | 8 | #include "Surface.h" 9 | 10 | namespace TM2IN { 11 | namespace Wall { 12 | /** 13 | * @ingroup geo_features 14 | * @brief Surface with at least one Triangle 15 | */ 16 | class TriangulatedSurface : public Surface{ 17 | 18 | public: 19 | std::vector triangles; 20 | 21 | TriangulatedSurface(); 22 | 23 | /** 24 | * @brief Constructor with Triangle 25 | */ 26 | TriangulatedSurface(Triangle& pl); 27 | 28 | /** 29 | * @brief Constructor with Triangle 30 | */ 31 | TriangulatedSurface(Triangle* pl) : TriangulatedSurface(*pl) {} 32 | 33 | /** 34 | * @brief Constructor with the other Surface 35 | */ 36 | TriangulatedSurface(TriangulatedSurface *pSurface); 37 | 38 | /** 39 | * @brief Validates with strict restriction 40 | */ 41 | bool strict_validation(); 42 | 43 | /** 44 | * @brief Validates with strict restriction 45 | */ 46 | bool easy_validation(); 47 | 48 | bool updateNormal() override; 49 | 50 | std::vector getNeighborList(); 51 | 52 | }; 53 | } 54 | } 55 | 56 | 57 | #endif //TM2IN_TRIANGULATEDSURFACE_H 58 | -------------------------------------------------------------------------------- /io/GenerationWriter.cpp: -------------------------------------------------------------------------------- 1 | #include "GenerationWriter.h" 2 | #include "io/json.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include "features/RoomBoundary/TriangulatedSurfaceMesh.h" 8 | #include "features/Wall/TriangulatedSurface.h" 9 | 10 | namespace TM2IN { 11 | namespace io { 12 | GenerationWriter* GenerationWriter::instance = NULL; 13 | void GenerationWriter::start(Room* room){ 14 | assert(this->mode == 0); 15 | this->room_name = room->geom_id; 16 | this->directory_path = Options::getInstance()->output_dir + "process/" + room->geom_id; 17 | if (boost::filesystem::exists(directory_path)) { 18 | boost::filesystem::remove_all(directory_path); 19 | } 20 | boost::filesystem::create_directories(directory_path); 21 | 22 | this->mode = 1; 23 | } 24 | 25 | void GenerationWriter::write(RoomBoundary::TriangulatedSurfaceMesh* tsm){ 26 | string output_path = this->directory_path + "/" + std::to_string(Options::getInstance()->generation) + ".json"; 27 | ofstream fout(output_path); 28 | fout << "{ \n"; 29 | fout << " \"spaces\" : [ \n"; 30 | string result; 31 | result = "{\n"; 32 | result += " \"name\" : \"" + this->room_name + "\", \n"; 33 | result += " \"Surfaces\" : [ \n"; 34 | for (unsigned int id = 0; id < tsm->surfaces.size(); id++) { 35 | result += TM2IN::detail::io::surface_to_json(*(tsm->surfaces[id])); 36 | if (id != tsm->surfaces.size() - 1) { 37 | result += ", \n"; 38 | } else { 39 | result += " \n"; 40 | } 41 | } 42 | result += "] \n"; 43 | result += "}"; 44 | fout << result << endl; 45 | fout << "]" << endl; 46 | fout << "}" << endl; 47 | fout.close(); 48 | } 49 | 50 | void GenerationWriter::write(vector& ts_list){ 51 | string output_path = this->directory_path + "/" + std::to_string(Options::getInstance()->generation) + ".json"; 52 | ofstream fout(output_path); 53 | fout << "{ \n"; 54 | fout << " \"spaces\" : [ \n"; 55 | string result; 56 | result = "{\n"; 57 | result += " \"name\" : \"" + this->room_name + "\", \n"; 58 | result += " \"Surfaces\" : [ \n"; 59 | for (unsigned int id = 0; id < ts_list.size(); id++) { 60 | result += TM2IN::detail::io::surface_to_json(*(ts_list[id])); 61 | if (id != ts_list.size() - 1) { 62 | result += ", \n"; 63 | } else { 64 | result += " \n"; 65 | } 66 | } 67 | result += "] \n"; 68 | result += "}"; 69 | fout << result << endl; 70 | fout << "]" << endl; 71 | fout << "}" << endl; 72 | fout.close(); 73 | } 74 | 75 | void GenerationWriter::close(){ 76 | this->mode = 0; 77 | } 78 | } 79 | } 80 | 81 | /* 82 | void GenerationWriter::start(Room* p_space){ 83 | this->space = p_space; 84 | 85 | //Create Generation directory 86 | if (boost::filesystem::exists(process_path + this->space->name)) { 87 | boost::filesystem::remove_all(process_path + this->space->name); 88 | } 89 | boost::filesystem::create_directories(process_path + this->space->name); 90 | 91 | ofstream statout; 92 | statout.open(process_path + this->space->name + "/gs" + ".txt", ios::out|ios::trunc); 93 | statout.close(); 94 | 95 | this->write(); 96 | } 97 | 98 | void GenerationWriter::write() { 99 | this->writeJSON(); 100 | this->writeStat(); 101 | } 102 | 103 | void GenerationWriter::writeJSON(){ 104 | ofstream fout; 105 | string f_path = process_path + this->space->name + "/g_" + to_string(this->space->generation) + ".json"; 106 | fout.open(f_path, ios::out|ios::trunc); 107 | 108 | if (!fout) return ; 109 | fout << this->space->asJsonText(); 110 | fout.close(); 111 | } 112 | 113 | 114 | void GenerationWriter::writeStat(){ 115 | ofstream statout; 116 | statout.open(process_path + this->space->name + "/gs" + ".txt", ios::app); 117 | statout << this->space->generation; 118 | statout << " , " << space->surfacesList.size(); 119 | statout << "\n"; 120 | statout.close(); 121 | } 122 | 123 | */ -------------------------------------------------------------------------------- /io/GenerationWriter.h: -------------------------------------------------------------------------------- 1 | #ifndef GenerationWriter_H_INCLUDED 2 | #define GenerationWriter_H_INCLUDED 3 | 4 | #include "features/Room.h" 5 | #include "util.h" 6 | #include 7 | 8 | using namespace std; 9 | using namespace TM2IN; 10 | 11 | namespace TM2IN { 12 | namespace io { 13 | class GenerationWriter{ 14 | private: 15 | GenerationWriter() {} 16 | 17 | static GenerationWriter *instance; 18 | 19 | int mode = 0; // 0 : wait, 1 : running 20 | string directory_path; 21 | string room_name; 22 | public: 23 | static GenerationWriter *getInstance() { 24 | if (!instance) { 25 | instance = new GenerationWriter(); 26 | } 27 | return instance; 28 | } 29 | 30 | void start(Room* room); 31 | 32 | void write(RoomBoundary::TriangulatedSurfaceMesh* tsm); 33 | void write(vector& ts_list); 34 | 35 | void close(); 36 | }; 37 | } 38 | } 39 | 40 | 41 | #endif // GenerationWriter_H_INCLUDED 42 | -------------------------------------------------------------------------------- /io/json.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | #include "detail/io/JsonWriter.h" 5 | 6 | #include "io/json.h" 7 | 8 | namespace TM2IN { 9 | namespace io { 10 | int exportRoomBoundaryJSON(string output_file, vector &rooms, int boundary_mode) { 11 | ofstream fout; 12 | fout.open(output_file); 13 | 14 | TM2IN::detail::io::JsonWriter writer(fout); 15 | writer.write(rooms, boundary_mode); 16 | fout.close(); 17 | return 0; 18 | } 19 | 20 | } 21 | } -------------------------------------------------------------------------------- /io/json.h: -------------------------------------------------------------------------------- 1 | #ifndef JSONMAKER_H_INCLUDED 2 | #define JSONMAKER_H_INCLUDED 3 | 4 | #include 5 | #include 6 | 7 | #include "features/IndoorComponent.h" 8 | 9 | using namespace std; 10 | 11 | namespace TM2IN{ 12 | namespace io { 13 | /** 14 | * @brief Export a vector of Room to Json format 15 | * @ingroup public_api 16 | */ 17 | int exportRoomBoundaryJSON(string output_file, vector &rooms, int boundary_mode=0); 18 | } 19 | }; 20 | 21 | #endif // JSONMAKER_H_INCLUDED 22 | -------------------------------------------------------------------------------- /io/max3ds.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 16. 3 | // 4 | 5 | #include "detail/io/ColladaReader.h" 6 | #include "detail/io/Max3DSReader.h" 7 | #include "detail/io/Max3DSWriter.h" 8 | #include "max3ds.h" 9 | 10 | #include 11 | 12 | using namespace std; 13 | 14 | namespace TM2IN{ 15 | namespace io{ 16 | std::vector import3DS(const char *filePath) { 17 | FILE *l_file; 18 | if ((l_file=fopen (filePath, "rb") ) == NULL){ 19 | throw std::runtime_error(string(filePath) + " cannot be open in import3DS"); 20 | } 21 | 22 | TM2IN::detail::io::Max3DSReader reader(l_file); 23 | return reader.read(); 24 | } 25 | 26 | 27 | int export3DS(const char *filePath, vector rooms) { 28 | FILE* pFile; 29 | pFile= fopen(filePath, "w"); 30 | if (!pFile) { 31 | throw std::runtime_error(string(filePath) + " cannot be open in export3DS"); 32 | } 33 | 34 | TM2IN::detail::io::Max3DSWriter writer(pFile); 35 | return writer.write(rooms); 36 | } 37 | 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /io/max3ds.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 16. 3 | // 4 | 5 | #ifndef TM2IN_MAX3DS_H 6 | #define TM2IN_MAX3DS_H 7 | 8 | #include "features/Room.h" 9 | 10 | namespace TM2IN{ 11 | namespace io{ 12 | /** 13 | * @ingroup public_api 14 | * @brief Imports 3DS file and returns a vector of Room. 15 | */ 16 | std::vector import3DS(const char *filePath); 17 | /** 18 | * @brief Export a vector of Room to 3DS format 19 | * @ingroup public_api 20 | */ 21 | int export3DS(const char *filePath, std::vector rooms); 22 | } 23 | } 24 | 25 | 26 | 27 | #endif //TM2IN_MAX3DS_H 28 | -------------------------------------------------------------------------------- /io/tvr.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 16. 3 | // 4 | 5 | #include 6 | #include "tvr.h" 7 | 8 | namespace TM2IN { 9 | namespace io { 10 | vector importTVR(const char *filePath) { 11 | ifstream fin; 12 | fin.open(filePath); 13 | 14 | assert(fin); 15 | 16 | TM2IN::detail::io::TVRReader reader(fin); 17 | return reader.read(); 18 | } 19 | } 20 | } 21 | 22 | 23 | /* 24 | void TriangleMesh::exportTVR(const char *path) { 25 | std::cout << "save As TVR" << endl; 26 | cout << path; 27 | FILE* pFile; 28 | pFile= fopen(path, "w"); 29 | fprintf(pFile, "TVR0\n"); 30 | 31 | for (int i = 0 ; i < this->vertices.size() ; i++){ 32 | ostringstream strStream; 33 | strStream << "v "; 34 | for (int j = 0 ; j < 3 ; j++){ 35 | strStream << this->vertices[i]->coords[j] << " "; 36 | } 37 | strStream << endl; 38 | string str = strStream.str(); 39 | fprintf(pFile, "%s", str.c_str()); 40 | } 41 | 42 | for (int group_i = 0 ; group_i < this->triangles.size() ; group_i++){ 43 | fprintf(pFile, "g %s\n", this->triangles[group_i].first.c_str()); 44 | for (int tri_i = 0 ; tri_i < this->triangles[group_i].second.size(); tri_i++){ 45 | Triangle* triangle = this->triangles[group_i].second[tri_i]; 46 | ostringstream strStream; 47 | strStream << "f "; 48 | for (int j = 0 ; j < 3 ; j++){ 49 | strStream << triangle->vertex(j)->index << " "; 50 | } 51 | strStream << endl; 52 | fprintf(pFile,"%s", strStream.str().c_str()); 53 | } 54 | } 55 | 56 | fclose(pFile); 57 | 58 | } 59 | */ 60 | 61 | /* 62 | * 63 | * 64 | int TVRImporter::extractMINtvr(string fileName){ 65 | ifstream fin; 66 | fin.open(fileName+".tvr"); 67 | 68 | ofstream fout; 69 | fout.open(fileName+".min.tvr"); 70 | if (!fin) return -1;//error 71 | 72 | string inputstr; 73 | getline(fin, inputstr); 74 | if (inputstr.find("TVR0") == string::npos){ 75 | cout << "different version : " << inputstr << endl; 76 | return -1; 77 | } 78 | else{ 79 | fout << "TVR0" << endl; 80 | } 81 | 82 | while(!fin.eof()){ 83 | getline(fin, inputstr); 84 | if (inputstr.size() < 3) continue; 85 | switch(inputstr.c_str()[0]){ 86 | case 'c':{ 87 | break; 88 | } 89 | case 'v':{ 90 | std::stringstream ss; 91 | ss.str(inputstr); 92 | string line; 93 | getline(ss, line, '\t'); 94 | fout << line << endl; 95 | break; 96 | } 97 | case 'g':{ 98 | fout << inputstr << endl; 99 | break; 100 | } 101 | case 'f':{ 102 | fout << inputstr << endl; 103 | break; 104 | } 105 | } 106 | } 107 | fout.close(); 108 | fin.close(); 109 | 110 | return 0; 111 | } 112 | 113 | 114 | 115 | Vertex* TVRImporter::findSameVertex(vector& vertices, Checker* check, Vertex& vt){ 116 | vector::iterator it, low; 117 | low = std::lower_bound(vertices.begin(), vertices.end(), vt.x() - check->threshold_same_vt_distance * 2, CompareVertex_X() ); 118 | 119 | for (it = low ; it != vertices.end() ; it++){ 120 | double diff = check->compare_vertex( (*it), &vt); 121 | if (diff > 0){ 122 | break; 123 | } 124 | else if (diff < 0){ 125 | continue; 126 | } 127 | else{ 128 | return *it; 129 | } 130 | } 131 | 132 | Vertex* new_vt = new Vertex(vt); 133 | vertices.insert(it, new_vt); 134 | 135 | return new_vt; 136 | } 137 | */ 138 | -------------------------------------------------------------------------------- /io/tvr.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 16. 3 | // 4 | 5 | #ifndef TM2IN_TVR_H 6 | #define TM2IN_TVR_H 7 | 8 | #include "features/IndoorComponent.h" 9 | 10 | namespace TM2IN{ 11 | namespace io{ 12 | /** 13 | * @ingroup public_api 14 | * @brief Imports TVR file and returns a vector of Room. 15 | */ 16 | std::vector importTVR(const char *filePath); 17 | 18 | } 19 | } 20 | 21 | 22 | #endif //TM2IN_TVR_H 23 | -------------------------------------------------------------------------------- /io/xml.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 16. 3 | // 4 | 5 | #include "xml.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace rapidxml; 15 | 16 | namespace TM2IN{ 17 | namespace io{ 18 | std::vector importDAE(const char *filePath) { 19 | ifstream pFile(filePath); 20 | 21 | TM2IN::detail::io::ColladaReader cr(pFile); 22 | return cr.read(); 23 | } 24 | 25 | int exportIndoorGML_infactory(const char *filePath, std::vector rooms) { 26 | ofstream pFile(filePath); 27 | TM2IN::detail::io::InFactoryClient ic(rooms); 28 | ic.make(); 29 | std::string xml_string = ic.getDocumentStr(); 30 | pFile << xml_string; 31 | pFile.close(); 32 | return 0; 33 | } 34 | 35 | int exportIndoorGML(const char *filePath, std::vector rooms) { 36 | std::ofstream pFile(filePath); 37 | 38 | TM2IN::detail::io::IndoorGMLWriter writer(pFile); 39 | return writer.write(rooms); 40 | } 41 | 42 | 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /io/xml.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by dongmin on 18. 7. 16. 3 | // 4 | 5 | #ifndef TM2IN_IO_XML_H 6 | #define TM2IN_IO_XML_H 7 | 8 | #include 9 | #include "features/Room.h" 10 | 11 | 12 | namespace TM2IN{ 13 | namespace io{ 14 | /** 15 | * @ingroup public_api 16 | * @brief Imports COLLADA(dae) file and returns a vector of Room. 17 | */ 18 | std::vector importDAE(const char *filePath); 19 | 20 | /** 21 | * @ingroup public_api 22 | * @brief export Data to IndoorGML model 23 | */ 24 | int exportIndoorGML_local(const char *filePath, std::vector rooms); 25 | 26 | /** 27 | * @ingroup public_api 28 | * @brief export Data to IndoorGML model 29 | */ 30 | int exportIndoorGML_infactory(const char *filePath, std::vector rooms); 31 | } 32 | } 33 | 34 | 35 | #endif //TM2IN_IO_XML_H 36 | -------------------------------------------------------------------------------- /util.cpp: -------------------------------------------------------------------------------- 1 | #include "util.h" 2 | 3 | #include "config.h" 4 | #include "Options.h" 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | template 11 | void split(const std::string &s, char delim, Out result) { 12 | std::stringstream ss; 13 | ss.str(s); 14 | std::string item; 15 | while (std::getline(ss, item, delim)) { 16 | *(result++) = item; 17 | } 18 | } 19 | 20 | std::vector split(const std::string &s, char delim) { 21 | std::vector elems; 22 | split(s, delim, std::back_inserter(elems)); 23 | return elems; 24 | } 25 | 26 | void printProcess(ull index, ull size, std::string str){ 27 | std::cout << "\r" << str << " ==========" << (int)((double)index/(double)size * 100) <<"% ========"; 28 | } 29 | 30 | void removeFilesInDirectory(std::string path){ 31 | DIR *theFolder = opendir(path.c_str()); 32 | struct dirent *next_file; 33 | char filepath[256]; 34 | 35 | while ( (next_file = readdir(theFolder)) != NULL ) 36 | { 37 | // build the path for each file in the folder 38 | sprintf(filepath, "%s/%s", path.c_str(), next_file->d_name); 39 | remove(filepath); 40 | } 41 | closedir(theFolder); 42 | } 43 | 44 | void createAndRemoveDir() { 45 | std::string resultPath = Options::getInstance()->output_dir; 46 | if (boost::filesystem::exists(resultPath)){ 47 | char ans; 48 | std::cout << "\n\nThis folder exist. Remove Files in directory? (y/n)" << std::endl; 49 | std::cin >> ans; 50 | if (ans == 'y' || ans == 'Y') 51 | boost::filesystem::remove_all(resultPath); 52 | } 53 | boost::filesystem::create_directory(resultPath); 54 | 55 | } -------------------------------------------------------------------------------- /util.h: -------------------------------------------------------------------------------- 1 | #ifndef UTIL_H_INCLUDED 2 | #define UTIL_H_INCLUDED 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | typedef long long ll; 16 | typedef unsigned long long ull; 17 | typedef std::vector> vll; 18 | 19 | std::vector split(const std::string &s, char delim); 20 | 21 | template 22 | void split(const std::string &s, char delim, Out result); 23 | void printProcess(ull index, ull size, std::string str); 24 | void removeFilesInDirectory(std::string path); 25 | void createAndRemoveDir(); 26 | 27 | 28 | #endif // UTIL_H_INCLUDED 29 | --------------------------------------------------------------------------------