├── .gitignore ├── 3rdParty ├── json │ └── nlohmann │ │ └── json.hpp └── meshoptimizer │ ├── LICENSE.md │ ├── Readme.txt │ ├── indexcodec.cpp │ ├── indexgenerator.cpp │ ├── meshoptimizer.h │ ├── overdrawanalyzer.cpp │ ├── overdrawoptimizer.cpp │ ├── simplifier.cpp │ ├── vcacheanalyzer.cpp │ ├── vcacheoptimizer.cpp │ ├── vfetchanalyzer.cpp │ └── vfetchoptimizer.cpp ├── CMakeLists.txt ├── DeveloperNotes.md ├── Dockerfile ├── LICENSE.txt ├── Readme.md ├── cmake └── modules │ ├── FindCTB.cmake │ └── FindGeographicLib.cmake ├── docker └── cesium-terrain-builder │ └── patches │ └── GDALTiler.cpp.patch ├── docs └── logos │ ├── EMODnet_col_all_vert.gif │ └── EMODnet_col_all_vert_doxygen_sizes.gif ├── doxyfile.cfg ├── scripts ├── create_layer_file.py ├── qm_tiler_large_files.py ├── simple_tiles_server.py ├── split_large_geotiff_to_vrt.py └── tests │ └── emodnet_esri_ascii_to_geotiff.py └── src ├── CMakeLists.txt ├── apps ├── CMakeLists.txt ├── dem2tin.cpp └── qm_tiler.cpp ├── base ├── borders_data.h ├── crs_conversions.cpp ├── crs_conversions.h ├── ellipsoid.h ├── gzip_file_reader.cpp ├── gzip_file_reader.h ├── gzip_file_writer.cpp ├── gzip_file_writer.h ├── legacy │ ├── global_geodetic.cpp │ └── global_geodetic.h ├── misc_utils.h ├── quantized_mesh.cpp ├── quantized_mesh.h ├── quantized_mesh_tile.cpp ├── quantized_mesh_tile.h ├── quantized_mesh_tiler.cpp ├── quantized_mesh_tiler.h ├── quantized_mesh_tiles_pyramid_builder.cpp ├── quantized_mesh_tiles_pyramid_builder.h ├── tile_border_vertices.h ├── zoom_tiles_border_vertices_cache.cpp ├── zoom_tiles_border_vertices_cache.h └── zoom_tiles_scheduler.h ├── cgal ├── Projection_traits_3_extended.h ├── border_edges_are_constrained_edge_map.h ├── cgal_utils.h ├── corner_vertices_are_constrained_vertex_map.h ├── detect_sharp_edges_without_borders.h ├── extract_polylines_from_sharp_edges.h ├── extract_tile_borders_from_polyhedron.h ├── further_constrained_placement.h ├── generate_border_features_polylines.h ├── legacy │ ├── Polyhedral_mesh_domain_with_features_3_extended.h │ ├── detect_polylines_in_polyhedron.h │ └── polyhedron_detect_sharp_features.h ├── point_set_features_simplification_cost.h ├── polyhedron_builder_from_c3t3_boundary.h ├── polyhedron_builder_from_projected_triangulation.h └── surface_mesh_from_projected_triangulation.h ├── dev-tests ├── CMakeLists.txt ├── Readme.md ├── compute_statistics.cpp ├── detect_features_without_borders.cpp ├── hierarchy_simplification.cpp ├── qm_parser.cpp ├── remesh_preserving_borders.cpp ├── simplify_preserving_border_edges.cpp ├── test_check_borders.cpp ├── test_read_write.cpp └── wlop_simplification.cpp └── tin_creation ├── CMakeLists.txt ├── tin_creation_cgal_types.h ├── tin_creation_delaunay_strategy.cpp ├── tin_creation_delaunay_strategy.h ├── tin_creation_greedy_insertion_strategy.cpp ├── tin_creation_greedy_insertion_strategy.h ├── tin_creation_remeshing_strategy.cpp ├── tin_creation_remeshing_strategy.h ├── tin_creation_simplification_lindstrom_turk_strategy.cpp ├── tin_creation_simplification_lindstrom_turk_strategy.h ├── tin_creation_simplification_point_set.cpp ├── tin_creation_simplification_point_set.h ├── tin_creation_simplification_point_set_grid.cpp ├── tin_creation_simplification_point_set_grid.h ├── tin_creation_simplification_point_set_hierarchy.cpp ├── tin_creation_simplification_point_set_hierarchy.h ├── tin_creation_simplification_point_set_random.cpp ├── tin_creation_simplification_point_set_random.h ├── tin_creation_simplification_point_set_wlop.cpp ├── tin_creation_simplification_point_set_wlop.h ├── tin_creation_utils.h ├── tin_creator.cpp └── tin_creator.h /.gitignore: -------------------------------------------------------------------------------- 1 | garbage/ 2 | -------------------------------------------------------------------------------- /3rdParty/meshoptimizer/LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016-2017 Arseny Kapoulkine 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /3rdParty/meshoptimizer/Readme.txt: -------------------------------------------------------------------------------- 1 | meshoptimizer library. Code obtained from: https://github.com/zeux/meshoptimizer 2 | 3 | 4 | -------------------------------------------------------------------------------- /3rdParty/meshoptimizer/indexgenerator.cpp: -------------------------------------------------------------------------------- 1 | // This file is part of meshoptimizer library; see meshoptimizer.h for version/license details 2 | #include "meshoptimizer.h" 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | namespace meshopt 10 | { 11 | 12 | static unsigned int murmurHash(const char* key, size_t len, unsigned int h) 13 | { 14 | const unsigned int m = 0x5bd1e995; 15 | const int r = 24; 16 | 17 | while (len >= 4) 18 | { 19 | unsigned int k = *reinterpret_cast(key); 20 | 21 | k *= m; 22 | k ^= k >> r; 23 | k *= m; 24 | 25 | h *= m; 26 | h ^= k; 27 | 28 | key += 4; 29 | len -= 4; 30 | } 31 | 32 | return h; 33 | } 34 | 35 | struct VertexHasher 36 | { 37 | const char* vertices; 38 | size_t vertex_size; 39 | 40 | unsigned int empty() const 41 | { 42 | return ~0u; 43 | } 44 | 45 | size_t operator()(unsigned int index) const 46 | { 47 | return murmurHash(vertices + index * vertex_size, vertex_size, 0); 48 | } 49 | 50 | size_t operator()(unsigned int lhs, unsigned int rhs) const 51 | { 52 | return memcmp(vertices + lhs * vertex_size, vertices + rhs * vertex_size, vertex_size) == 0; 53 | } 54 | }; 55 | 56 | struct VertexHashEntry 57 | { 58 | unsigned int key; 59 | unsigned int value; 60 | }; 61 | 62 | template 63 | static void hashInit(std::vector& table, const Hash& hash, size_t count) 64 | { 65 | size_t buckets = 1; 66 | while (buckets < count) 67 | buckets *= 2; 68 | 69 | T dummy = T(); 70 | dummy.key = hash.empty(); 71 | 72 | table.clear(); 73 | table.resize(buckets, dummy); 74 | } 75 | 76 | template 77 | static T* hashLookup(std::vector& table, const Hash& hash, const Key& key) 78 | { 79 | assert(table.size() > 0); 80 | assert((table.size() & (table.size() - 1)) == 0); 81 | 82 | size_t hashmod = table.size() - 1; 83 | size_t bucket = hash(key) & hashmod; 84 | 85 | for (size_t probe = 0; probe <= hashmod; ++probe) 86 | { 87 | T& item = table[bucket]; 88 | 89 | if (item.key == hash.empty()) 90 | return &item; 91 | 92 | if (hash(item.key, key)) 93 | return &item; 94 | 95 | // hash collision, quadratic probing 96 | bucket = (bucket + probe + 1) & hashmod; 97 | } 98 | 99 | assert(false && "Hash table is full"); 100 | return 0; 101 | } 102 | 103 | } // namespace meshopt 104 | 105 | size_t meshopt_generateVertexRemap(unsigned int* destination, const unsigned int* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size) 106 | { 107 | using namespace meshopt; 108 | 109 | assert(indices || index_count == vertex_count); 110 | assert(index_count % 3 == 0); 111 | assert(vertex_size > 0 && vertex_size <= 256); 112 | 113 | for (size_t i = 0; i < vertex_count; ++i) 114 | { 115 | destination[i] = ~0u; 116 | } 117 | 118 | VertexHasher hasher = {static_cast(vertices), vertex_size}; 119 | 120 | std::vector table; 121 | hashInit(table, hasher, vertex_count); 122 | 123 | unsigned int next_vertex = 0; 124 | 125 | for (size_t i = 0; i < index_count; ++i) 126 | { 127 | unsigned int index = indices ? indices[i] : unsigned(i); 128 | assert(index < vertex_count); 129 | 130 | if (destination[index] == ~0u) 131 | { 132 | VertexHashEntry* entry = hashLookup(table, hasher, index); 133 | 134 | if (entry->key == ~0u) 135 | { 136 | entry->key = index; 137 | entry->value = next_vertex++; 138 | } 139 | 140 | destination[index] = entry->value; 141 | } 142 | } 143 | 144 | assert(next_vertex <= vertex_count); 145 | 146 | return next_vertex; 147 | } 148 | 149 | void meshopt_remapVertexBuffer(void* destination, const void* vertices, size_t vertex_count, size_t vertex_size, const unsigned int* remap) 150 | { 151 | assert(destination != vertices); 152 | assert(vertex_size > 0 && vertex_size <= 256); 153 | 154 | for (size_t i = 0; i < vertex_count; ++i) 155 | { 156 | if (remap[i] != ~0u) 157 | { 158 | assert(remap[i] < vertex_count); 159 | 160 | memcpy(static_cast(destination) + remap[i] * vertex_size, static_cast(vertices) + i * vertex_size, vertex_size); 161 | } 162 | } 163 | } 164 | 165 | void meshopt_remapIndexBuffer(unsigned int* destination, const unsigned int* indices, size_t index_count, const unsigned int* remap) 166 | { 167 | assert(index_count % 3 == 0); 168 | 169 | for (size_t i = 0; i < index_count; ++i) 170 | { 171 | unsigned int index = indices ? indices[i] : unsigned(i); 172 | assert(remap[index] != ~0u); 173 | 174 | destination[i] = remap[index]; 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /3rdParty/meshoptimizer/vcacheanalyzer.cpp: -------------------------------------------------------------------------------- 1 | // This file is part of meshoptimizer library; see meshoptimizer.h for version/license details 2 | #include "meshoptimizer.h" 3 | 4 | #include 5 | 6 | #include 7 | 8 | meshopt_VertexCacheStatistics meshopt_analyzeVertexCache(const unsigned int* indices, size_t index_count, size_t vertex_count, unsigned int cache_size, unsigned int warp_size, unsigned int buffer_size) 9 | { 10 | assert(index_count % 3 == 0); 11 | assert(cache_size >= 3); 12 | assert(warp_size == 0 || warp_size >= 3); 13 | 14 | meshopt_VertexCacheStatistics result = {}; 15 | 16 | unsigned int warp_offset = 0; 17 | unsigned int buffer_offset = 0; 18 | 19 | std::vector cache_timestamps(vertex_count, 0); 20 | unsigned int timestamp = cache_size + 1; 21 | 22 | for (size_t i = 0; i < index_count; i += 3) 23 | { 24 | unsigned int a = indices[i + 0], b = indices[i + 1], c = indices[i + 2]; 25 | assert(a < vertex_count && b < vertex_count && c < vertex_count); 26 | 27 | bool ac = (timestamp - cache_timestamps[a]) > cache_size; 28 | bool bc = (timestamp - cache_timestamps[b]) > cache_size; 29 | bool cc = (timestamp - cache_timestamps[c]) > cache_size; 30 | 31 | // flush cache if triangle doesn't fit into warp or into the triangle buffer 32 | if ((buffer_size && buffer_offset == buffer_size) || (warp_size && warp_offset + ac + bc + cc > warp_size)) 33 | { 34 | result.warps_executed += warp_offset > 0; 35 | 36 | warp_offset = 0; 37 | buffer_offset = 0; 38 | 39 | // reset cache 40 | timestamp += cache_size + 1; 41 | } 42 | 43 | // update cache and add vertices to warp 44 | for (int j = 0; j < 3; ++j) 45 | { 46 | unsigned int index = indices[i + j]; 47 | 48 | if (timestamp - cache_timestamps[index] > cache_size) 49 | { 50 | cache_timestamps[index] = timestamp++; 51 | result.vertices_transformed++; 52 | warp_offset++; 53 | } 54 | } 55 | 56 | buffer_offset++; 57 | } 58 | 59 | result.warps_executed += warp_offset > 0; 60 | 61 | result.acmr = index_count == 0 ? 0 : float(result.vertices_transformed) / float(index_count / 3); 62 | result.atvr = vertex_count == 0 ? 0 : float(result.vertices_transformed) / float(vertex_count); 63 | 64 | return result; 65 | } 66 | -------------------------------------------------------------------------------- /3rdParty/meshoptimizer/vfetchanalyzer.cpp: -------------------------------------------------------------------------------- 1 | // This file is part of meshoptimizer library; see meshoptimizer.h for version/license details 2 | #include "meshoptimizer.h" 3 | 4 | #include 5 | 6 | meshopt_VertexFetchStatistics meshopt_analyzeVertexFetch(const unsigned int* indices, size_t index_count, size_t vertex_count, size_t vertex_size) 7 | { 8 | assert(index_count % 3 == 0); 9 | assert(vertex_size > 0 && vertex_size <= 256); 10 | 11 | meshopt_VertexFetchStatistics result = {}; 12 | 13 | const size_t kCacheLine = 64; 14 | const size_t kCacheSize = 128 * 1024; 15 | 16 | // simple direct mapped cache; on typical mesh data this is close to 4-way cache, and this model is a gross approximation anyway 17 | size_t cache[kCacheSize / kCacheLine] = {}; 18 | 19 | for (size_t i = 0; i < index_count; ++i) 20 | { 21 | unsigned int index = indices[i]; 22 | assert(index < vertex_count); 23 | 24 | size_t start_address = index * vertex_size; 25 | size_t end_address = start_address + vertex_size; 26 | 27 | size_t start_tag = start_address / kCacheLine; 28 | size_t end_tag = (end_address + kCacheLine - 1) / kCacheLine; 29 | 30 | assert(start_tag < end_tag); 31 | 32 | for (size_t tag = start_tag; tag < end_tag; ++tag) 33 | { 34 | size_t line = tag % (sizeof(cache) / sizeof(cache[0])); 35 | 36 | // we store +1 since cache is filled with 0 by default 37 | result.bytes_fetched += (cache[line] != tag + 1) * kCacheLine; 38 | cache[line] = tag + 1; 39 | } 40 | } 41 | 42 | result.overfetch = vertex_count == 0 ? 0 : float(result.bytes_fetched) / float(vertex_count * vertex_size); 43 | 44 | return result; 45 | } 46 | -------------------------------------------------------------------------------- /3rdParty/meshoptimizer/vfetchoptimizer.cpp: -------------------------------------------------------------------------------- 1 | // This file is part of meshoptimizer library; see meshoptimizer.h for version/license details 2 | #include "meshoptimizer.h" 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | 11 | // Modified to also return the vertex remap table (Ricard Campos) 12 | size_t meshopt_optimizeVertexFetch(void* destination, unsigned int* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size, unsigned int* vertex_remap) 13 | { 14 | assert(index_count % 3 == 0); 15 | assert(vertex_size > 0 && vertex_size <= 256); 16 | 17 | // support in-place optimization 18 | std::vector vertices_copy; 19 | 20 | if (destination == vertices) 21 | { 22 | vertices_copy.assign(static_cast(vertices), static_cast(vertices) + vertex_count * vertex_size); 23 | vertices = &vertices_copy[0]; 24 | } 25 | 26 | // // build vertex remap table 27 | // std::vector vertex_remap(vertex_count, ~0u); 28 | 29 | unsigned int next_vertex = 0; 30 | 31 | for (size_t i = 0; i < index_count; ++i) 32 | { 33 | unsigned int index = indices[i]; 34 | assert(index < vertex_count); 35 | 36 | unsigned int& remap = vertex_remap[index]; 37 | 38 | if (remap == ~0u) // vertex was not added to destination VB 39 | { 40 | // add vertex 41 | memcpy(static_cast(destination) + next_vertex * vertex_size, static_cast(vertices) + index * vertex_size, vertex_size); 42 | 43 | remap = next_vertex++; 44 | } 45 | 46 | // modify indices in place 47 | indices[i] = remap; 48 | } 49 | 50 | assert(next_vertex <= vertex_count); 51 | 52 | return next_vertex; 53 | } 54 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | project("EMODnet Quantized Mesh Generator for Cesium") 3 | 4 | # ----------------------------------------------------------------------------- 5 | # Extent the module path 6 | # ----------------------------------------------------------------------------- 7 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules") 8 | 9 | # ----------------------------------------------------------------------------- 10 | # Default build options 11 | # ----------------------------------------------------------------------------- 12 | 13 | # C++11 related 14 | include(CheckCXXCompilerFlag) 15 | CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11) 16 | CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X) 17 | 18 | if(NOT MSVC) 19 | if(COMPILER_SUPPORTS_CXX11) 20 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 21 | elseif(COMPILER_SUPPORTS_CXX0X) 22 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -pthread") 23 | else() 24 | message(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.") 25 | endif() 26 | endif() 27 | 28 | # ----------------------------------------------------------------------------- 29 | # Required packages 30 | # ----------------------------------------------------------------------------- 31 | 32 | # PThreads 33 | find_package(Threads REQUIRED) 34 | 35 | # CGAL library 36 | find_package(CGAL) 37 | include( ${CGAL_USE_FILE} ) 38 | 39 | # Boost library 40 | find_package(Boost COMPONENTS program_options 41 | filesystem 42 | system 43 | REQUIRED) 44 | if(NOT Boost_FOUND) 45 | message(FATAL_ERROR "The boost library cannot be found on the system, required!") 46 | endif() 47 | 48 | message("Boost libs = ${Boost_LIBRARIES}") 49 | 50 | # ZLib library 51 | find_package(ZLIB) 52 | if(NOT ZLIB_FOUND) 53 | message(FATAL_ERROR "The zlib library cannot be found on the system, required!") 54 | endif() 55 | include_directories(${ZLIB_INCLUDE_DIRS}) 56 | 57 | # Cesium-terrain-builder library 58 | find_package(CTB) 59 | if(NOT CTB_FOUND) 60 | message(FATAL_ERROR "Cesium-Terrain-Builder not found, required!") 61 | endif() 62 | include_directories(${CTB_INCLUDE_DIR}) 63 | 64 | # GDAL library 65 | find_package(GDAL) 66 | if(NOT GDAL_FOUND) 67 | message(FATAL_ERROR "The GDAL library cannot be found on the system") 68 | endif() 69 | include_directories(${GDAL_INCLUDE_DIRS}) 70 | 71 | # Doxygen for documentation 72 | find_package(Doxygen) 73 | if(DOXYGEN_FOUND) 74 | configure_file(${CMAKE_CURRENT_SOURCE_DIR}/doxyfile.cfg ${CMAKE_CURRENT_BINARY_DIR}/doxyfile @ONLY) 75 | add_custom_target(doc 76 | ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/doxyfile 77 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} 78 | COMMENT "Generating API documentation with Doxygen" VERBATIM 79 | ) 80 | endif(DOXYGEN_FOUND) 81 | 82 | # Project-related include dirs 83 | include_directories("src") 84 | include_directories("3rdParty") 85 | include_directories("3rdParty/json") 86 | 87 | # ----------------------------------------------------------------------------- 88 | # Compilation 89 | # ----------------------------------------------------------------------------- 90 | include(GNUInstallDirs) 91 | add_subdirectory("src") 92 | -------------------------------------------------------------------------------- /DeveloperNotes.md: -------------------------------------------------------------------------------- 1 | # Developer Notes 2 | 3 | ## Decisions taken 4 | 5 | * While the QuantizedMesh class has read/write capabilities for the quantized mesh format with both oct-encoded per-vertex normals and water masks, the quantized mesh tiles generated by qm_tiler do not include the water mask. 6 | * While simplification results in a higher zoom level could be used as starting point for lower levels in the pyramid, we choose to always sample for each tile the dataset at the resolution required by the zoom level. This is because we treat each tile individually, and we are not sure we can assure the simplification quality at the tiles' edges to be the as required. 7 | 8 | ## TODOs 9 | 10 | * Decouple the tile limits from the tile simplifier. As it is now, the conversion ECEF coordinates needed by the point set simplification methods assumes that the input uses a lat/lon/height system. This is too restrictive, and should be generalized. 11 | * Find a way to sample large rasters without getting out of memory. 12 | * In dem2tin, it is not straightforward to use the point set methods with gdal rasters. In qm_tiler, since we use libctb for gathering the raster tiles, the tiles are already in the global geodetic SRS, so the transformations that we compute internally to ECEF coordinates assume that everything is in that SRS. However, because of how we have it implemented now, we don't have a straightforward way of computing this from a GDAL raster with an arbitrary SRS. 13 | 14 | ## Issues to take into account when implementing the quantized-mesh format 15 | * The vertices and indices need to be optimized for both cache and fetching to be suitable for highwatermark encoding. We use a slightly modified version of the meshoptimizer library (https://github.com/zeux/meshoptimizer) to perform these steps. 16 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | 3 | # Install dependencies available through apt-get 4 | RUN apt-get update -y && apt-get install -y \ 5 | git \ 6 | cmake \ 7 | wget \ 8 | build-essential \ 9 | pkg-config \ 10 | bash-completion \ 11 | zlib1g-dev \ 12 | libboost-all-dev \ 13 | libcgal-dev \ 14 | libproj-dev \ 15 | python3 \ 16 | libnetcdf-dev 17 | 18 | # Download and install the gdal version that works with Cesium Terrain Builder (avoids the "undefined reference to `GDALCreateOverviewDataset(GDALDataset*" error) 19 | WORKDIR /opt/ 20 | RUN wget http://download.osgeo.org/gdal/2.1.0/gdal-2.1.0.tar.gz 21 | RUN tar -xvzf gdal-2.1.0.tar.gz 22 | WORKDIR gdal-2.1.0 23 | RUN ./configure --with-python 24 | RUN make -j$(nproc) 25 | RUN make install 26 | 27 | # Clone and install Cesium Terrain Builder 28 | # Note: need to patch the src/GDALTiler.cpp file (cannot compile otherwise because of the same "undefined reference to `GDALCreateOverviewDataset(GDALDataset*" error mentioned above) 29 | WORKDIR /opt/ 30 | RUN git clone https://github.com/geo-data/cesium-terrain-builder.git 31 | ADD ./docker/cesium-terrain-builder/patches/GDALTiler.cpp.patch /tmp/GDALTiler.cpp.patch 32 | RUN patch /opt/cesium-terrain-builder/src/GDALTiler.cpp /tmp/GDALTiler.cpp.patch 33 | RUN mkdir /opt/cesium-terrain-builder/build 34 | WORKDIR /opt/cesium-terrain-builder/build 35 | RUN cmake .. 36 | RUN make -j$(nproc) 37 | RUN make install 38 | RUN ldconfig 39 | 40 | # Copy the required files inside the image 41 | ADD . /usr/local/src/emodnet_qmgc 42 | RUN mkdir /usr/local/src/emodnet_qmgc/build 43 | WORKDIR /usr/local/src/emodnet_qmgc/build 44 | RUN cmake .. 45 | RUN make -j$(nproc) 46 | RUN make install 47 | RUN ldconfig 48 | 49 | # Move also the python scripts to be part of the command line tools 50 | RUN cp /usr/local/src/emodnet_qmgc/scripts/*.py /usr/local/bin 51 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # EMODnet Quantized Mesh Generator for Cesium 2 | 3 | Library for generating terrain tiles in Cesium's quantized-mesh format from a GDAL raster file. 4 | 5 | ## Requirements 6 | 7 | This project depends on the following C++ libraries: 8 | 9 | * Boost (program_options): http://www.boost.org/ 10 | * ZLib: https://www.zlib.net/ 11 | * Cesium Terrain Builder (libctb): https://github.com/geo-data/cesium-terrain-builder 12 | * GDAL: http://www.gdal.org/ 13 | * CGAL: https://www.cgal.org/ (tested with version 4.12.1) 14 | * meshoptimizer: https://github.com/zeux/meshoptimizer (with small modifications, source included in this project) 15 | * JSON for modern C++: https://github.com/nlohmann/json (source included in this project) 16 | 17 | Also, Python is required to run the scripts provided. 18 | 19 | ## Compilation 20 | 21 | This project uses the typical cmake pipeline. Thus, assuming that all the libraries listed above are installed, it should be as easy as: 22 | 23 | ``` 24 | mkdir build 25 | cd build 26 | cmake .. 27 | make 28 | ``` 29 | 30 | Optionally, you can create the documentation using: 31 | 32 | ``` 33 | make doc 34 | ``` 35 | 36 | An already compiled version of the documentation can be found in the [web of this project](https://coronis-computing.github.io/emodnet_qmgc/html/index.html). 37 | 38 | ## Usage 39 | 40 | The main functionality of the project is provided by the `qm_tiler` app. A simple usage is: 41 | 42 | ``` 43 | qm_tiler -i -o 44 | ``` 45 | 46 | However, the method has many parameters that may be tuned, and that are explained in the [wiki](https://github.com/coronis-computing/emodnet_qmgc/wiki). You can list them by running: 47 | 48 | ``` 49 | qm_tiler -h 50 | ``` 51 | 52 | After creating the TMS pyramid of tiles, use the script `create_layer_file.py` to create the `layer.json` file required by Cesium. 53 | 54 | Finally, in order to easily test the project, we also provide the `simple_tiles_server.py`, which creates a simple web server of tiles. 55 | 56 | Please refer to the [wiki](https://github.com/coronis-computing/emodnet_qmgc/wiki) page of this project for further information. 57 | 58 | ## Known issues 59 | 60 | * As previously stated, this project depends on Cesium Terrain Builder library (https://github.com/geo-data/cesium-terrain-builder), and thus it shares the same limitation when creating tiles at lower zoom levels from large DEMs. In this case, an error similar to the following one may raise: 61 | 62 | ``` 63 | ERROR 1: Integer overflow : nSrcXSize=20979, nSrcYSize=28800 64 | ERROR 1: IReadBlock failed at X offset 0, Y offset 0 65 | terminate called after throwing an instance of 'ctb::CTBException' 66 | ``` 67 | 68 | * If the case above raises, you can use the provided `qm_tiler_large_images.py` python script, which basically automates the solution proposed in Cesium Terrain Builder's documentation (https://github.com/geo-data/cesium-terrain-builder). 69 | 70 | ## Acknowledgements 71 | 72 | This project has been developed by Coronis Computing S.L. within the EMODnet Bathymetry project. 73 | 74 | * EMODnet: http://www.emodnet.eu/ 75 | * EMODnet (bathymetry): http://www.emodnet-bathymetry.eu/ 76 | * Coronis: http://www.coronis.es 77 | -------------------------------------------------------------------------------- /cmake/modules/FindCTB.cmake: -------------------------------------------------------------------------------- 1 | # Look for cesium-terrain-builder library in common dirs or env vars 2 | # Author: Ricard Campos (rcampos@eia.udg.edu) 3 | 4 | # Check for cmake/env-defined vars 5 | set( CTB_INCLUDE_SEARCH_PATHS ${CTB_INCLUDE_HITS} $ENV{CTB_INCLUDE_HITS} ) 6 | set( CTB_LIBRARY_SEARCH_PATHS ${CTB_LIBRARY_HINTS} $ENV{CTB_LIBRARY_HINTS} ) 7 | 8 | # Check include in common paths 9 | FIND_PATH(CTB_INCLUDE_DIR NAMES TerrainTile.hpp 10 | PATHS 11 | ${CTB_INCLUDE_SEARCH_PATHS} 12 | /usr/include/ctb 13 | /usr/include 14 | /opt/local/include 15 | /opt/local/include/ctb 16 | /usr/local/include 17 | /usr/local/include/ctb 18 | /sw/include 19 | /sw/include/ctb 20 | ) 21 | 22 | # Check library in common paths 23 | FIND_LIBRARY(CTB_LIBRARY NAMES libctb.so 24 | PATHS 25 | ${CTB_LIBRARY_HINTS} 26 | /usr/lib/ctb 27 | /usr/lib 28 | /opt/local/lib 29 | /opt/local/lib/ctb 30 | /usr/local/lib 31 | /usr/local/lib/ctb 32 | /sw/lib 33 | /sw/lib/ctb 34 | ) 35 | 36 | include(FindPackageHandleStandardArgs) 37 | find_package_handle_standard_args(ctb "Could NOT find Cesium-Terrain-Builder\nNOTE: If you don't have CTB installed in default system paths, you should set CTB_INCLUDE_HINTS and CTB_LIBRARY_HINTS variables (either in cmake or as environment vars).\n" CTB_INCLUDE_DIR CTB_LIBRARY ) 38 | 39 | -------------------------------------------------------------------------------- /cmake/modules/FindGeographicLib.cmake: -------------------------------------------------------------------------------- 1 | # Find the GeographicLib library 2 | # 3 | # Variables set: 4 | # GEOGRAPHICLIB_FOUND = TRUE 5 | # GeographicLib_INCLUDE_DIRS 6 | # GeographicLib_LIBRARIES 7 | # GeographicLib_LIBRARY_DIRS 8 | # 9 | # Author: Ricard Campos (rcampos@eia.udg.edu) 10 | 11 | find_library ( GeographicLib_LIBRARIES 12 | NAMES Geographic 13 | PATHS /usr/local 14 | /usr/local/lib 15 | /opt/local/lib 16 | /sw/lib ) 17 | 18 | if (GeographicLib_LIBRARIES) 19 | get_filename_component( GeographicLib_LIBRARY_DIRS "${GeographicLib_LIBRARIES}" PATH ) 20 | endif () 21 | 22 | find_path( GeographicLib_INCLUDE_DIRS 23 | NAMES GeographicLib/Config.h 24 | PATHS /usr/include 25 | /opt/local/include 26 | /usr/local/include 27 | /sw/include ) 28 | 29 | # (From CMake doc) If the variables to are all valid, then _FOUND will be set to TRUE. If DEFAULT_MSG is given as second argument, then the function will generate itself useful success and error messages. 30 | include (FindPackageHandleStandardArgs) 31 | find_package_handle_standard_args( GeographicLib 32 | DEFAULT_MSG 33 | GeographicLib_LIBRARY_DIRS 34 | GeographicLib_LIBRARIES GeographicLib_INCLUDE_DIRS ) 35 | 36 | # (From CMake doc) Mark the named cached variables as advanced. An advanced variable will not be displayed in any of the cmake GUIs unless the show advanced option is on. 37 | mark_as_advanced( GeographicLib_LIBRARY_DIRS 38 | GeographicLib_LIBRARIES 39 | GeographicLib_INCLUDE_DIRS ) 40 | -------------------------------------------------------------------------------- /docker/cesium-terrain-builder/patches/GDALTiler.cpp.patch: -------------------------------------------------------------------------------- 1 | --- /cesium-terrain-builder_original/src/GDALTiler.cpp 2020-08-05 09:17:40.542643329 +0200 2 | +++ src/GDALTiler.cpp 2018-09-13 11:42:23.585035227 +0200 3 | @@ -246,7 +246,7 @@ 4 | if( iOvr >= 0 ) 5 | { 6 | //std::cout << "CTB WARPING: Selecting overview level " << iOvr << " for output dataset " << nPixels << "x" << nLines << std::endl; 7 | - poSrcOvrDS = GDALCreateOverviewDataset( poSrcDS, iOvr, FALSE); 8 | + poSrcOvrDS = GDALCreateOverviewDataset( poSrcDS, iOvr, FALSE, FALSE); 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /docs/logos/EMODnet_col_all_vert.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coronis-computing/emodnet_qmgc/036aa9c1a2948351da1ce4ccc93811da78edfaee/docs/logos/EMODnet_col_all_vert.gif -------------------------------------------------------------------------------- /docs/logos/EMODnet_col_all_vert_doxygen_sizes.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coronis-computing/emodnet_qmgc/036aa9c1a2948351da1ce4ccc93811da78edfaee/docs/logos/EMODnet_col_all_vert_doxygen_sizes.gif -------------------------------------------------------------------------------- /scripts/create_layer_file.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import argparse 4 | import json 5 | import os 6 | 7 | 8 | # Returns a list with the folders in a given directory 9 | def get_folders(dir): 10 | dir_cnt = os.listdir(dir) 11 | return [name for name in dir_cnt if os.path.isdir(os.path.join(dir, name))] 12 | 13 | # Returns a list with the files in a given directory 14 | def get_files(dir): 15 | dir_cnt = os.listdir(dir) 16 | return [name for name in dir_cnt if os.path.isfile(os.path.join(dir, name))] 17 | 18 | # DevNote: the following two functions come from gdal2tiles sources: 19 | def TileBounds(tx, ty, zoom): 20 | "Returns bounds of the given tile" 21 | tileSize = 256 22 | res = 180.0 / tileSize / 2**zoom 23 | return ( 24 | tx*tileSize*res - 180, 25 | ty*tileSize*res - 90, 26 | (tx+1)*tileSize*res - 180, 27 | (ty+1)*tileSize*res - 90 28 | ) 29 | 30 | def TileLatLonBounds(tx, ty, zoom): 31 | "Returns bounds of the given tile in the SWNE form" 32 | b = TileBounds(tx, ty, zoom) 33 | return (b[1],b[0],b[3],b[2]) 34 | 35 | # Main function 36 | if __name__ == '__main__': 37 | #Parameters 38 | parser = argparse.ArgumentParser(description="Creates the layer.json file required by Cesium from a TMS folder structure (quantized-mesh format assumed)") 39 | parser.add_argument("tms_dir", action="store", type=str, help="The root of a TMS directory in Cesium''s quantized-mesh format. The generated layer.json file will be created here") 40 | 41 | param = parser.parse_args() 42 | 43 | # Base layer.json data 44 | data = {"tilejson": "2.1.0", "format": "quantized-mesh-1.0", "version": "1.2.0", "scheme": "tms", "tiles": ["{z}/{x}/{y}.terrain?v={version}"], "attribution": "Terrain Data,Author: Created using the EMODnet Quantized Mesh Generator for Cesium", "projection": "EPSG:4326"} 45 | 46 | # Get the zoom levels 47 | 48 | # List of folders in the base level 49 | list_zoom_dirs = get_folders(param.tms_dir) 50 | list_zoom_ints = map(int, list_zoom_dirs) # As integers 51 | 52 | # Extract the minimum and maximum zoom from the available dirs 53 | data["minzoom"] = min(list_zoom_ints) 54 | data["maxzoom"] = max(list_zoom_ints) 55 | 56 | # Get the limits for each zoom 57 | list_zoom_ints = sorted(list_zoom_ints) 58 | 59 | available = [] 60 | for folder_x_int in list_zoom_ints: 61 | cur_limits = {} 62 | folder_x = str(folder_x_int) 63 | 64 | # --- Limits in X --- 65 | dir_cnt_X = get_folders(os.path.join(param.tms_dir, folder_x)) 66 | dir_cnt_X_ints = map(int, dir_cnt_X) # As integers 67 | cur_limits["startX"] = min(dir_cnt_X_ints) 68 | cur_limits["endX"] = max(dir_cnt_X_ints) 69 | 70 | # --- Limits in Y --- 71 | dir_cnt_Y = get_files(os.path.join(param.tms_dir, folder_x, dir_cnt_X[0])) # We use the first folder in X, they are all supposed to have the same number of tiles and with the same numbering 72 | dir_cnt_Y = [f.replace(".terrain", "") for f in dir_cnt_Y] # Remove the ".terrain" part of the files 73 | dir_cnt_Y_ints = map(int, dir_cnt_Y) # As integers 74 | cur_limits["startY"] = min(dir_cnt_Y_ints) 75 | cur_limits["endY"] = max(dir_cnt_Y_ints) 76 | 77 | cur_limits_list = [cur_limits] 78 | available.append(cur_limits_list) 79 | 80 | # Compute the bounds of the map based on the coordinates of the tiles in the deeper zoom level 81 | deeper_limits = available[data["maxzoom"]][0] 82 | s, w, _, _ = TileLatLonBounds(deeper_limits["startX"], deeper_limits["startY"], data["maxzoom"]) 83 | _, _, n, e = TileLatLonBounds(deeper_limits["endX"], deeper_limits["endY"], data["maxzoom"]) 84 | 85 | data["bounds"] = [w, s, e, n] 86 | data["available"] = available 87 | 88 | # Write JSON file 89 | with open(param.tms_dir + "/layer.json", 'w') as outfile: 90 | json.dump(data, outfile, indent = 4) 91 | -------------------------------------------------------------------------------- /scripts/simple_tiles_server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import argparse 3 | import os 4 | try: 5 | # python 2 6 | from SimpleHTTPServer import SimpleHTTPRequestHandler 7 | from BaseHTTPServer import HTTPServer as BaseHTTPServer 8 | except ImportError: 9 | # python 3 10 | from http.server import HTTPServer as BaseHTTPServer, SimpleHTTPRequestHandler 11 | import SocketServer 12 | 13 | 14 | 15 | class CORSRequestHandler(SimpleHTTPRequestHandler): 16 | def end_headers (self): 17 | self.send_header('Access-Control-Allow-Origin', '*') 18 | self.send_header('Access-Control-Allow-Methods', 'GET,OPTIONS') 19 | self.send_header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept') 20 | self.send_header('Cache-Control', 'public,max-age=31536000') 21 | 22 | # Add the 'Content-Encoding: gzip' header for the terrain tiles 23 | path = self.translate_path(self.path) 24 | filename, file_extension = os.path.splitext(path) 25 | if file_extension == ".terrain": 26 | self.send_header('Content-Encoding', 'gzip') 27 | 28 | self.extensions_map.update({'.terrain': 'application/vnd.quantized-mesh'}) 29 | SimpleHTTPRequestHandler.end_headers(self) 30 | 31 | 32 | 33 | if __name__ == '__main__': 34 | parser = argparse.ArgumentParser(description="Sets up a simple http server with the CORS headers needed for serving " 35 | "quantized mesh tiles") 36 | parser.add_argument("folder", type=str, default='./', help="Folder to serve") 37 | parser.add_argument("-p", dest="port", type=int, default=8000, help="The port the server will be listening to") 38 | param = parser.parse_args() 39 | 40 | print("Serving folder " + param.folder + " at port " + str(param.port)) 41 | 42 | # Change the current folder 43 | os.chdir(param.folder) 44 | 45 | Handler = CORSRequestHandler 46 | httpd = SocketServer.TCPServer(("", param.port), Handler) 47 | 48 | httpd.serve_forever() -------------------------------------------------------------------------------- /scripts/split_large_geotiff_to_vrt.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import argparse 4 | import os 5 | import subprocess 6 | import gdal 7 | 8 | 9 | def main(): 10 | parser = argparse.ArgumentParser(description="Converts EMODnet ESRI Ascii files into geotiffs and copies the georeferencing from the RGB geotiffs") 11 | parser.add_argument("input_tif", action="store", type=str, help="The TIFF file to split") 12 | parser.add_argument('--tile_size_x', dest='tile_size_x', type=int, default=1024, help="The size of the tiles' size in X") 13 | parser.add_argument('--tile_size_y', dest='tile_size_y', type=int, default=1024, help="The size of the tiles' size in Y") 14 | parser.add_argument('-o', dest='output_dir', type=str, default='./out', help="The output folder where the tiles and the VRT file will be created") 15 | param = parser.parse_args() 16 | 17 | # File name base 18 | file_base = os.path.basename(param.input_tif) 19 | file_stem = os.path.splitext(file_base)[0] 20 | 21 | # Create the output dir if not existing 22 | if not os.access(param.output_dir, os.F_OK): 23 | os.mkdir(param.output_dir) 24 | 25 | # Extract the WKT from the geotiff 26 | wkt_str = subprocess.check_output(["gdalsrsinfo", "-o", "wkt", param.input_tif]) 27 | wkt_str = wkt_str.rstrip('\n') # Remove newline chars 28 | 29 | # Open a GDAL dataset with the geotiff as input 30 | ds = gdal.Open(param.input_tif) 31 | band = ds.GetRasterBand(1) 32 | xsize = band.XSize 33 | ysize = band.YSize 34 | 35 | # Split the image 36 | for i in range(0, xsize, param.tile_size_x): 37 | for j in range(0, ysize, param.tile_size_y): 38 | cmd = "gdal_translate -of GTIFF -srcwin " + str(i)+ ", " + str(j) + ", " + str(param.tile_size_x) + ", " + str(param.tile_size_y) + " " + param.input_tif + " " + param.output_dir + "/" + file_stem + "_x" + str(i) + "_y" + str(j) + ".tif" 39 | os.system(cmd) 40 | 41 | # Create a VRT file joining the resulting geotiffs, to ease use in GDAL 42 | cmd = "gdalbuildvrt " + param.output_dir + "/" + file_stem + ".vrt" + " " + param.output_dir + "/*.tif" 43 | os.system(cmd) 44 | 45 | 46 | 47 | if __name__ == '__main__': 48 | main() 49 | -------------------------------------------------------------------------------- /scripts/tests/emodnet_esri_ascii_to_geotiff.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import argparse 4 | import sys 5 | from PIL import Image 6 | from xml.dom import minidom 7 | import glob 8 | import os 9 | from osgeo import osr 10 | import subprocess 11 | import re 12 | 13 | 14 | def natural_sort(l): 15 | convert = lambda text: int(text) if text.isdigit() else text.lower() 16 | alphanum_key = lambda key: [ convert(c) for c in re.split('([0-9]+)', key) ] 17 | return sorted(l, key = alphanum_key) 18 | 19 | 20 | def main(): 21 | parser = argparse.ArgumentParser(description="Converts EMODnet ESRI Ascii files into geotiffs and copies the georeferencing from the RGB geotiffs") 22 | parser.add_argument('--input_esri_folder', dest='input_esri_folder', type=str, default='./', help="The input folder containing the ESRI Ascii files to convert") 23 | parser.add_argument('--input_geotiff_folder', dest='input_geotif_folder', type=str, help="The input folder containing the geotiff images from where we will extract the wkt") 24 | parser.add_argument('-of', dest='output_folder', type=str, default='./out', help="The output folder where georeferenced tiffs will be stored") 25 | parser.add_argument('--vrt_file', dest='vrt_file', type=str, default="", help="If specified, generates a VRT file joining all the geotiffs into a single dataset. This file will be stored in the output folder.") 26 | param = parser.parse_args() 27 | 28 | # Georeference each tiff image 29 | files = glob.glob(param.input_esri_folder+"/*.asc") 30 | print files 31 | 32 | if not os.access(param.output_folder, os.F_OK): 33 | os.mkdir(param.output_folder) 34 | 35 | output_files = [] 36 | for file in files: 37 | file_base = os.path.basename(file) 38 | file_stem = os.path.splitext(file_base)[0] 39 | 40 | # Extract the WKT from the RGB geotiffs 41 | ref_geotif_file = param.input_geotif_folder + "/" + file_stem +"_rgb.tif" 42 | print ref_geotif_file 43 | wkt_str = subprocess.check_output(["gdalsrsinfo", "-o", "wkt", ref_geotif_file]) 44 | wkt_str = wkt_str.rstrip('\n') # Remove newline chars 45 | 46 | output_file = file_stem+"_geo.tif" 47 | output_file_full_path = param.output_folder+"/"+output_file 48 | cmd = "gdal_translate -of GTiff -a_srs " + wkt_str + " " + file_base + " " + output_file_full_path 49 | print cmd 50 | os.system(cmd) 51 | 52 | output_files.append(output_file) 53 | 54 | if param.vrt_file: 55 | print "VRT file creation is not working yet, do it manually!" 56 | #os.system("cd " + param.output_folder) 57 | #cmd = "gdalbuildvrt " + param.vrt_file + " ".join(output_files) 58 | #print cmd 59 | #os.system(cmd) 60 | 61 | 62 | 63 | if __name__ == '__main__': 64 | main() 65 | 66 | 67 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include_directories(base) 2 | include_directories(apps) 3 | 4 | add_subdirectory(tin_creation) 5 | add_subdirectory(apps) 6 | add_subdirectory(dev-tests) 7 | -------------------------------------------------------------------------------- /src/apps/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # qm_tiler app 2 | add_executable(qm_tiler qm_tiler.cpp 3 | ../base/quantized_mesh_tile.cpp 4 | ../base/gzip_file_reader.cpp 5 | ../base/gzip_file_writer.cpp 6 | ../base/quantized_mesh.cpp 7 | ../base/quantized_mesh_tiler.cpp 8 | ../../3rdParty/meshoptimizer/vcacheoptimizer.cpp 9 | ../../3rdParty/meshoptimizer/vfetchoptimizer.cpp 10 | ../base/zoom_tiles_border_vertices_cache.cpp 11 | ../base/quantized_mesh_tiles_pyramid_builder.cpp) 12 | target_link_libraries(qm_tiler TinCreation 13 | ${Boost_LIBRARIES} 14 | ${ZLIB_LIBRARIES} 15 | ${CTB_LIBRARY} 16 | ${CGAL_LIBRARIES} 17 | ${GDAL_LIBRARY}) 18 | 19 | if(THREADS_HAVE_PTHREAD_ARG) 20 | target_compile_options(qm_tiler PUBLIC "-pthread") 21 | endif() 22 | if(CMAKE_THREAD_LIBS_INIT) 23 | target_link_libraries(qm_tiler "${CMAKE_THREAD_LIBS_INIT}") 24 | endif() 25 | 26 | # dem2tin app 27 | add_executable(dem2tin dem2tin.cpp) 28 | target_link_libraries(dem2tin TinCreation ${Boost_LIBRARIES} ${CGAL_LIBRARIES} ${GDAL_LIBRARY} ${CMAKE_THREAD_LIBS_INIT}) 29 | 30 | if(THREADS_HAVE_PTHREAD_ARG) 31 | target_compile_options(dem2tin PUBLIC "-pthread") 32 | endif() 33 | if(CMAKE_THREAD_LIBS_INIT) 34 | target_link_libraries(dem2tin "${CMAKE_THREAD_LIBS_INIT}") 35 | endif() 36 | 37 | install(TARGETS qm_tiler dem2tin DESTINATION bin) -------------------------------------------------------------------------------- /src/base/crs_conversions.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Coronis Computing S.L. (Spain) 2 | // All rights reserved. 3 | // 4 | // This file is part of EMODnet Quantized Mesh Generator for Cesium. 5 | // 6 | // This program is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | // Author: Ricard Campos (ricardcd@gmail.com) 20 | 21 | #include "crs_conversions.h" 22 | 23 | namespace crs_conversions 24 | { 25 | 26 | void llh2ecef( const double& lat, const double& lon, const double& h, 27 | double& x, double& y, double& z ) 28 | { 29 | // Constants for the WGS84 Ellipsoid 30 | const double wgs84_a = 6378137.0; // Semi-major axis 31 | const double wgs84_e2 = 6.6943799901377997e-3; // First eccentricity squared 32 | 33 | // First convert lat/lon to radians 34 | double latRad = lat*(M_PI/180.0); 35 | double lonRad = lon*(M_PI/180.0); 36 | 37 | double n = wgs84_a/sqrt( 1 - wgs84_e2*sin( latRad )*sin( latRad ) ); 38 | x = ( n + h )*cos( latRad )*cos( lonRad ); // ECEF x 39 | y = ( n + h )*cos( latRad )*sin( lonRad ); // ECEF y 40 | z = ( n*(1 - wgs84_e2 ) + h )*sin( latRad ); //ECEF z 41 | } 42 | 43 | void ecef2llh( const double& x, const double& y, const double& z, 44 | double& lat, double& lon, double& h ) 45 | { 46 | // Constants for the WGS84 Ellipsoid 47 | const double wgs84_a = 6378137.0; // Semi-major axis 48 | const double wgs84_a2 = wgs84_a*wgs84_a; // Semi-major axis squared 49 | const double wgs84_e2 = 6.6943799901377997e-3; // First eccentricity squared 50 | const double wgs84_b = 6356752.3142451793; // Semi-minor axis 51 | const double wgs84_b2 = wgs84_b*wgs84_b; // Semi-minor axis squared 52 | 53 | double ep = sqrt((wgs84_a2 - wgs84_b2)/wgs84_b2); 54 | double p = sqrt(x*x + y*y); 55 | double th = atan2(wgs84_a*z, wgs84_b*p); 56 | lon = atan2(y, x); 57 | lat = atan2( z + (ep*ep) * wgs84_b * (sin(th)*sin(th)*sin(th)), 58 | p - wgs84_e2 * wgs84_a * (cos(th)*cos(th)*cos(th)) ); 59 | double N = wgs84_a/sqrt(1 - wgs84_e2 * (sin(lat)*sin(lat))); 60 | h = (p/cos(lat)) - N; 61 | 62 | // Radians to degrees 63 | lon *= 180./M_PI; 64 | lat *= 180./M_PI; 65 | } 66 | 67 | } // End namespace crs_conversions -------------------------------------------------------------------------------- /src/base/crs_conversions.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Coronis Computing S.L. (Spain) 2 | // All rights reserved. 3 | // 4 | // This file is part of EMODnet Quantized Mesh Generator for Cesium. 5 | // 6 | // This program is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | // Author: Ricard Campos (ricardcd@gmail.com) 20 | 21 | #ifndef EMODNET_QMGC_CRS_CONVERSIONS_H 22 | #define EMODNET_QMGC_CRS_CONVERSIONS_H 23 | 24 | #include 25 | 26 | /*! @namespace crs_conversions 27 | @brief Simple CRS conversions tools 28 | */ 29 | namespace crs_conversions 30 | { 31 | /** 32 | * @brief Converts from Latitude Longitude to Earth-Centered Earth-Fixed coordinates 33 | * @param lat Latitude (in degrees) 34 | * @param lon Longitude (in degrees) 35 | * @param h Height (in meters) 36 | * @param x Earth-Centered Earth-Fixed X 37 | * @param y Earth-Centered Earth-Fixed Y 38 | * @param z Earth-Centered Earth-Fixed Z 39 | */ 40 | void llh2ecef( const double& lat, const double& lon, const double& h, 41 | double& x, double& y, double& z ); 42 | 43 | /** 44 | * @brief Converts from Earth-Centered Earth-Fixed to Latitude Longitude coordinates 45 | * @param x Earth-Centered Earth-Fixed X 46 | * @param y Earth-Centered Earth-Fixed Y 47 | * @param z Earth-Centered Earth-Fixed Z 48 | * @param lat Latitude (in degrees) 49 | * @param lon Longitude (in degrees) 50 | * @param h Height (in meters) 51 | */ 52 | void ecef2llh( const double& x, const double& y, const double& z, 53 | double& lat, double& lon, double& h ); 54 | } // End namespace crs_conversions 55 | 56 | #endif // EMODNET_QMGC_CONVERSIONS_H 57 | -------------------------------------------------------------------------------- /src/base/ellipsoid.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Coronis Computing S.L. (Spain) 2 | // All rights reserved. 3 | // 4 | // This file is part of EMODnet Quantized Mesh Generator for Cesium. 5 | // 6 | // This program is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | // Author: Ricard Campos (ricardcd@gmail.com) 20 | 21 | #ifndef EMODNET_QMGC_ELLIPSOID_H 22 | #define EMODNET_QMGC_ELLIPSOID_H 23 | 24 | /** 25 | * @class Ellipsoid 26 | * @brief Describes an ellipsoid. 27 | * 28 | * A quadratic surface of the form (x / rx)^2 + (y / ry)^2 + (z / rz)^2 = 1. 29 | * The ellipsoid chosen has implications in the Quantized Mesh format, specially for computing the occlusion point of a 30 | * Quantized Mesh tile. 31 | */ 32 | class Ellipsoid 33 | { 34 | public: 35 | /** 36 | * @brief Constructor 37 | * @param rx Radius of the ellipsoid in X 38 | * @param ry Radius of the ellipsoid in Y 39 | * @param rz Radius of the ellipsoid in Z 40 | */ 41 | Ellipsoid( const double& rx, const double& ry, const double& rz ) : m_rx(rx), m_ry(ry), m_rz(rz) {} 42 | 43 | /// Default constructor (all radius set to 0) 44 | Ellipsoid() : m_rx(0.0), m_ry(0.0), m_rz(0.0) {} 45 | 46 | /** 47 | * @brief Copy constructor 48 | * @param e The ellipsoid to copy 49 | */ 50 | Ellipsoid( const Ellipsoid& e ) { 51 | m_rx = e.getRadiusX() ; 52 | m_ry = e.getRadiusY() ; 53 | m_rz = e.getRadiusZ() ; 54 | } 55 | 56 | /// Get the X radius of the ellipsoid 57 | double getRadiusX() const { return m_rx ; } 58 | 59 | /// Get the Y radius of the ellipsoid 60 | double getRadiusY() const { return m_ry ; } 61 | 62 | /// Get the Z radius of the ellipsoid 63 | double getRadiusZ() const { return m_rz ; } 64 | 65 | /// Set the X radius of the ellipsoid 66 | void setRadiusX(const double& rx) { m_rx = rx ; } 67 | 68 | /// Set the Y radius of the ellipsoid 69 | void setRadiusY(const double& ry) { m_ry = ry ; } 70 | 71 | /// Set the Z radius of the ellipsoid 72 | void setRadiusZ(const double& rz) { m_rz = rz ; } 73 | 74 | protected: 75 | double m_rx; //!< Radius of the ellipsoid in X 76 | double m_ry; //!< Radius of the ellipsoid in Y 77 | double m_rz; //!< Radius of the ellipsoid in Z 78 | }; 79 | 80 | /** 81 | * @class WGS84Ellipsoid 82 | * @brief The WGS84 ellipsoid 83 | * 84 | * An instance of the WGS84 ellipsoid 85 | */ 86 | class WGS84Ellipsoid : public Ellipsoid 87 | { 88 | public: 89 | /** 90 | * @brief Constructor 91 | */ 92 | WGS84Ellipsoid() : Ellipsoid(6378137.0, 6378137.0, 6356752.3142451793) {} 93 | }; 94 | 95 | #endif //EMODNET_QMGC_ELLIPSOID_H 96 | -------------------------------------------------------------------------------- /src/base/gzip_file_reader.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Coronis Computing S.L. (Spain) 2 | // All rights reserved. 3 | // 4 | // This file is part of EMODnet Quantized Mesh Generator for Cesium. 5 | // 6 | // This program is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | // Author: Ricard Campos (ricardcd@gmail.com) 20 | 21 | #include "gzip_file_reader.h" 22 | 23 | GZipFileReader::GZipFileReader( const std::string &filePath ) 24 | { 25 | m_file = gzopen(filePath.c_str(), "rb") ; 26 | m_pos = 0 ; 27 | } 28 | 29 | 30 | 31 | Byte GZipFileReader::readByte() 32 | { 33 | return this->read() ; 34 | } 35 | 36 | 37 | 38 | void GZipFileReader::skipBytes( int numBytes ) { 39 | for ( int i = 0; i < numBytes; i++ ) { 40 | this->readByte() ; 41 | } 42 | } 43 | 44 | 45 | 46 | double GZipFileReader::readDouble() 47 | { 48 | return this->read() ; 49 | } 50 | 51 | 52 | 53 | float GZipFileReader::readFloat() 54 | { 55 | return this->read() ; 56 | } 57 | 58 | 59 | 60 | int GZipFileReader::readInt() 61 | { 62 | return this->read() ; 63 | } 64 | 65 | 66 | 67 | unsigned int GZipFileReader::readUInt() 68 | { 69 | return this->read() ; 70 | } 71 | 72 | 73 | 74 | short GZipFileReader::readShort() 75 | { 76 | return this->read() ; 77 | } 78 | 79 | 80 | 81 | unsigned short GZipFileReader::readUShort() 82 | { 83 | return this->read() ; 84 | } 85 | 86 | 87 | 88 | char GZipFileReader::readChar() 89 | { 90 | return this->read() ; 91 | } 92 | 93 | 94 | 95 | unsigned char GZipFileReader::readUChar() 96 | { 97 | return this->read() ; 98 | } -------------------------------------------------------------------------------- /src/base/gzip_file_reader.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Coronis Computing S.L. (Spain) 2 | // All rights reserved. 3 | // 4 | // This file is part of EMODnet Quantized Mesh Generator for Cesium. 5 | // 6 | // This program is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | // Author: Ricard Campos (ricardcd@gmail.com) 20 | 21 | #ifndef EMODNET_QMGC_GZIP_FILE_READER_H 22 | #define EMODNET_QMGC_GZIP_FILE_READER_H 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | /** 29 | * @class GZipFileReader 30 | * @brief Helper class to read a GZip file. 31 | */ 32 | class GZipFileReader { 33 | 34 | public: 35 | // Typedefs 36 | typedef unsigned char Byte; 37 | 38 | /// Constructor 39 | GZipFileReader( const std::string &filePath ); 40 | 41 | /// Check if the file is open 42 | bool isFileOpen() { return m_file != NULL; } 43 | 44 | /// Reads a byte 45 | Byte readByte(); 46 | 47 | /// Skips a given number of bytes 48 | void skipBytes(int numBytes); 49 | 50 | /// Reads a double 51 | double readDouble(); 52 | 53 | /// Reads a float 54 | float readFloat(); 55 | 56 | /// Reads a int 57 | int readInt(); 58 | 59 | /// Reads an unsigned int 60 | unsigned int readUInt(); 61 | 62 | /// Reads a short 63 | short readShort(); 64 | 65 | /// Reads an unsigned short 66 | unsigned short readUShort(); 67 | 68 | /// Reads a char 69 | char readChar(); 70 | 71 | /// Reads an unsigned char 72 | unsigned char readUChar(); 73 | 74 | /// Generic templated read function 75 | template 76 | T read() { 77 | // Size of the type used 78 | int sz = sizeof(T); 79 | 80 | // Read from the GZip file 81 | Byte buffer[sz]; 82 | int bytesRead = gzread(m_file, buffer, sz); 83 | T ret; 84 | memcpy(&ret, &buffer[0], sz); 85 | 86 | // Update the position of the pointer in the file 87 | m_pos += sz; 88 | 89 | return ret; 90 | } 91 | 92 | /// Returns the position on the file (i.e., read byte counter) 93 | int getPos() { return m_pos; } 94 | 95 | /// Closes the file 96 | bool close() { return gzclose(m_file); } 97 | 98 | /// Indicates the end of file 99 | bool eof() { return gzeof(m_file); } 100 | 101 | private: 102 | gzFile m_file; //!< The file to read 103 | int m_pos; //!< The position on the file (byte index) 104 | }; 105 | 106 | 107 | #endif //EMODNET_QMGC_GZIP_FILE_READER_H 108 | -------------------------------------------------------------------------------- /src/base/gzip_file_writer.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Coronis Computing S.L. (Spain) 2 | // All rights reserved. 3 | // 4 | // This file is part of EMODnet Quantized Mesh Generator for Cesium. 5 | // 6 | // This program is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | // Author: Ricard Campos (ricardcd@gmail.com) 20 | 21 | #include "gzip_file_writer.h" 22 | 23 | 24 | GZipFileWriter::GZipFileWriter( const std::string &filePath ) 25 | { 26 | m_file = gzopen(filePath.c_str(), "wb") ; 27 | m_pos = 0 ; 28 | } 29 | 30 | 31 | 32 | int GZipFileWriter::writeByte( const Byte &b ) 33 | { 34 | return this->write(b) ; 35 | } 36 | 37 | 38 | 39 | int GZipFileWriter::writeDouble( const double &d ) 40 | { 41 | return this->write(d) ; 42 | } 43 | 44 | 45 | 46 | int GZipFileWriter::writeFloat( const float &f ) 47 | { 48 | return this->write(f) ; 49 | } 50 | 51 | 52 | 53 | int GZipFileWriter::writeInt( const int &i ) 54 | { 55 | return this->write(i) ; 56 | } 57 | 58 | 59 | 60 | int GZipFileWriter::writeUInt( const unsigned int &u ) 61 | { 62 | return this->write(u) ; 63 | } 64 | 65 | 66 | 67 | int GZipFileWriter::writeShort( const short &s ) 68 | { 69 | return this->write(s) ; 70 | } 71 | 72 | 73 | 74 | int GZipFileWriter::writeUShort( const unsigned short &u ) 75 | { 76 | return this->write(u) ; 77 | } 78 | 79 | 80 | 81 | int GZipFileWriter::writeChar( const char &c ) 82 | { 83 | return this->write(c) ; 84 | } 85 | 86 | 87 | 88 | int GZipFileWriter::writeUChar( const unsigned char &c ) 89 | { 90 | return this->write(c) ; 91 | } 92 | -------------------------------------------------------------------------------- /src/base/gzip_file_writer.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Coronis Computing S.L. (Spain) 2 | // All rights reserved. 3 | // 4 | // This file is part of EMODnet Quantized Mesh Generator for Cesium. 5 | // 6 | // This program is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | // Author: Ricard Campos (ricardcd@gmail.com) 20 | 21 | #ifndef EMODNET_QMGC_GZIP_FILE_WRITER_H 22 | #define EMODNET_QMGC_GZIP_FILE_WRITER_H 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | /** 29 | * @class GZipFileWriter 30 | * @brief Helper class to write a GZip file. 31 | */ 32 | class GZipFileWriter { 33 | public: 34 | // Typedefs 35 | typedef unsigned char Byte ; 36 | 37 | /// Constructor 38 | GZipFileWriter( const std::string &filePath ) ; 39 | 40 | /// Check if the file is open 41 | bool isFileOpen() { return m_file != NULL ; } 42 | 43 | /// Writes a byte 44 | int writeByte( const Byte &b ) ; 45 | 46 | /// Writes a double 47 | int writeDouble( const double &d ) ; 48 | 49 | /// Writes a float 50 | int writeFloat( const float &f ) ; 51 | 52 | /// Writes an int 53 | int writeInt( const int &i ) ; 54 | 55 | /// Writes an unsigned int 56 | int writeUInt( const unsigned int &u ) ; 57 | 58 | /// Writes a short 59 | int writeShort( const short &s ) ; 60 | 61 | /// Writes an unsigned short 62 | int writeUShort( const unsigned short &u ) ; 63 | 64 | /// Writes a char 65 | int writeChar( const char &c ) ; 66 | 67 | /// Writes an unsigned char 68 | int writeUChar( const unsigned char &c ) ; 69 | 70 | /** 71 | * @brief Generic templated write function 72 | * 73 | * @return The number of written bytes, 0 means error 74 | */ 75 | template 76 | int write( T val ) { 77 | // Size of the type used 78 | int sz = sizeof(T) ; 79 | 80 | // Write to the GZip file 81 | // Byte buffer[sz]; 82 | // memcpy( &buffer[0], &val, sz ) ; 83 | int bytesWritten = gzwrite( m_file, reinterpret_cast(&val), sz ) ; 84 | 85 | // Update the position of the pointer in the file 86 | m_pos += sz ; 87 | 88 | return bytesWritten ; 89 | } 90 | 91 | /// Returns the position on the file (i.e., read byte counter) 92 | int getPos() { return m_pos ; } 93 | 94 | /// Closes the file 95 | bool close() { return gzclose(m_file) ; } 96 | 97 | private: 98 | gzFile m_file ; //!< The file to read 99 | int m_pos ; //!< The position on the file (byte index) 100 | }; 101 | 102 | 103 | #endif //EMODNET_QMGC_GZIP_FILE_WRITER_H 104 | -------------------------------------------------------------------------------- /src/base/legacy/global_geodetic.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Coronis Computing S.L. (Spain) 2 | // All rights reserved. 3 | // 4 | // This file is part of EMODnet Quantized Mesh Generator for Cesium. 5 | // 6 | // This program is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | // Author: Ricard Campos (ricardcd@gmail.com) 20 | 21 | #include "global_geodetic.h" 22 | #include 23 | 24 | 25 | 26 | GlobalGeodetic::GlobalGeodetic( bool tmsCompatible, int tileSize ) 27 | { 28 | m_tileSize = tileSize ; 29 | if ( tmsCompatible ) { 30 | m_resFact = 180.0 / m_tileSize ; 31 | m_numberOfLevelZeroTilesX = 2 ; 32 | m_numberOfLevelZeroTilesY = 1 ; 33 | } 34 | else { 35 | m_resFact = 360.0 / m_tileSize ; 36 | m_numberOfLevelZeroTilesX = 1 ; 37 | m_numberOfLevelZeroTilesY = 1 ; 38 | } 39 | } 40 | 41 | 42 | 43 | //! Converts lon/lat to pixel coordinates in given zoom of the EPSG:4326 pyramid 44 | void GlobalGeodetic::lonLatToPixels( const double &lon, const double &lat, const int &zoom, double& px, double py ) 45 | { 46 | double res = m_resFact / pow( 2 , zoom ) ; 47 | px = (180 + lon) / res ; 48 | py = (90 + lat) / res ; 49 | } 50 | 51 | 52 | 53 | //! Returns coordinates of the tile covering region in pixel coordinates 54 | void GlobalGeodetic::pixelsToTile( const double &px, const double &py, int tx, int ty ) 55 | { 56 | if ( px > 0 ) 57 | tx = (int) ceil( px / m_tileSize ) - 1 ; 58 | else 59 | tx = 0 ; 60 | if ( py > 0 ) 61 | ty = (int) ceil( py / m_tileSize ) - 1 ; 62 | else 63 | ty = 0 ; 64 | } 65 | 66 | 67 | 68 | //! Returns the tile for zoom which covers given lon/lat coordinates 69 | void GlobalGeodetic::lonLatToTile(const double &lon, const double &lat, const int &zoom, int tx, int ty ) 70 | { 71 | double px, py ; 72 | lonLatToPixels( lon, lat, zoom, px, py ) ; 73 | pixelsToTile( px, py, tx, ty ) ; 74 | } 75 | 76 | 77 | 78 | //! Resolution (arc/pixel) for given zoom level (measured at Equator) 79 | double GlobalGeodetic::resolution( const int &zoom ) 80 | { 81 | return m_resFact / pow( 2 , zoom ) ; 82 | } 83 | 84 | 85 | 86 | //! Maximal scaledown zoom of the pyramid closest to the pixelSize 87 | int GlobalGeodetic::zoomForPixelSize( const double &pixelSize ) 88 | { 89 | for ( int i = 0; i < MAXZOOMLEVEL; i++ ) { 90 | if ( pixelSize > resolution(i) ) { 91 | if ( i != 0 ) 92 | return i-1 ; 93 | else 94 | return 0 ; 95 | } 96 | } 97 | } 98 | 99 | 100 | 101 | //! Returns bounds of the given tile in the SWNE form 102 | TileBounds GlobalGeodetic::tileLatLonBounds( const int &tx, const int &ty, const int& zoom ) 103 | { 104 | TileBounds bounds ; 105 | double res = resolution( zoom ) ; 106 | bounds.minLongitude = tx * m_tileSize * res - 180 ; 107 | bounds.maxLongitude = (tx + 1) * m_tileSize * res - 180 ; 108 | bounds.minLatitude = ty * m_tileSize * res - 90 ; 109 | bounds.maxLatitude = (ty + 1) * m_tileSize * res - 90 ; 110 | 111 | return bounds ; 112 | } 113 | 114 | 115 | 116 | //! Returns the number of tiles over x at a given zoom level (only 256px) 117 | int GlobalGeodetic::getNumberOfXTilesAtZoom( const int &zoom ) 118 | { 119 | m_numberOfLevelZeroTilesX << zoom ; 120 | } 121 | 122 | 123 | 124 | //! Returns the number of tiles over y at a given zoom level (only 256px) 125 | int GlobalGeodetic::getNumberOfYTilesAtZoom( const int &zoom ) 126 | { 127 | m_numberOfLevelZeroTilesY << zoom ; 128 | } 129 | 130 | 131 | 132 | -------------------------------------------------------------------------------- /src/base/legacy/global_geodetic.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Coronis Computing S.L. (Spain) 2 | // All rights reserved. 3 | // 4 | // This file is part of EMODnet Quantized Mesh Generator for Cesium. 5 | // 6 | // This program is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | // Author: Ricard Campos (ricardcd@gmail.com) 20 | 21 | // 22 | // Reimplementation in C++ of the global_geodetic.py file from quantized_mesh_tile project 23 | // https://github.com/loicgasser/quantized-mesh-tile/blob/master/quantized_mesh_tile/global_geodetic.py 24 | // 25 | 26 | #ifndef EMODNET_QMGC_GLOBAL_GEODETIC_H 27 | #define EMODNET_QMGC_GLOBAL_GEODETIC_H 28 | 29 | #define MAXZOOMLEVEL 32 30 | 31 | struct TileBounds { 32 | double minLatitude ; 33 | double minLongitude ; 34 | double maxLatitude ; 35 | double maxLongitude ; 36 | 37 | TileBounds() { 38 | minLatitude = -1 ; 39 | minLongitude = -1 ; 40 | maxLatitude = -1 ; 41 | maxLongitude = -1 ; 42 | } 43 | 44 | }; 45 | 46 | 47 | class GlobalGeodetic { 48 | 49 | public: 50 | 51 | GlobalGeodetic( bool tmsCompatible = true, int tileSize = 256 ) ; 52 | 53 | //! Converts lon/lat to pixel coordinates in given zoom of the EPSG:4326 pyramid 54 | void lonLatToPixels( const double &lon, const double &lat, const int &zoom, double& px, double py ) ; 55 | 56 | //! Returns coordinates of the tile covering region in pixel coordinates 57 | void pixelsToTile( const double &px, const double &py, int tx, int ty ) ; 58 | 59 | //! Returns the tile for zoom which covers given lon/lat coordinates 60 | void lonLatToTile(const double &lon, const double &lat, const int &zoom, int tx, int ty ) ; 61 | 62 | //! Resolution (arc/pixel) for given zoom level (measured at Equator) 63 | double resolution( const int &zoom ) ; 64 | 65 | //! Maximal scaledown zoom of the pyramid closest to the pixelSize 66 | int zoomForPixelSize( const double &pixelSize ) ; 67 | 68 | //! Returns bounds of the given tile in the SWNE form 69 | TileBounds tileLatLonBounds( const int &tx, const int &ty, const int& zoom ) ; 70 | 71 | //! Returns the number of tiles over x at a given zoom level (only 256px) 72 | int getNumberOfXTilesAtZoom( const int &zoom ) ; 73 | 74 | //! Returns the number of tiles over y at a given zoom level (only 256px) 75 | int getNumberOfYTilesAtZoom( const int &zoom ) ; 76 | 77 | private: 78 | int m_tileSize ; 79 | double m_resFact ; 80 | int m_numberOfLevelZeroTilesX ; 81 | int m_numberOfLevelZeroTilesY ; 82 | 83 | }; 84 | 85 | 86 | #endif //EMODNET_QMGC_GLOBAL_GEODETIC_H 87 | -------------------------------------------------------------------------------- /src/base/misc_utils.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Coronis Computing S.L. (Spain) 2 | // All rights reserved. 3 | // 4 | // This file is part of EMODnet Quantized Mesh Generator for Cesium. 5 | // 6 | // This program is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | // Author: Ricard Campos (ricardcd@gmail.com) 20 | 21 | #ifndef EMODNET_QMGC_MISC_UTILS_H 22 | #define EMODNET_QMGC_MISC_UTILS_H 23 | 24 | /** 25 | * Remapping function. Changes a value in the range \p minOr \p maxOr to a value in the range \p minDest \p maxDest 26 | * @param value Value to remap 27 | * @param minOr Minium value in the original range 28 | * @param maxOr Maximum value in the original range 29 | * @param minDest Minimum value in the destination range 30 | * @param maxDest Maximum value in the destination range 31 | * @return Remapped value 32 | */ 33 | static double remap(const double& value, const double& minOr, const double& maxOr, const double& minDest, const double& maxDest) { 34 | if ( maxOr-minOr == 0 ) // Avoid division by zero 35 | return 0 ; 36 | else 37 | return ( (value-minOr)/(maxOr-minOr) ) * (maxDest-minDest) + minDest ; 38 | } 39 | 40 | #endif //EMODNET_QMGC_MISC_UTILS_H 41 | -------------------------------------------------------------------------------- /src/base/quantized_mesh_tile.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Coronis Computing S.L. (Spain) 2 | // All rights reserved. 3 | // 4 | // This file is part of EMODnet Quantized Mesh Generator for Cesium. 5 | // 6 | // This program is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | // Author: Ricard Campos (ricardcd@gmail.com) 20 | 21 | #include "quantized_mesh_tile.h" 22 | #include "tin_creation/tin_creation_cgal_types.h" 23 | #include "cgal/cgal_utils.h" 24 | #include 25 | 26 | 27 | 28 | void QuantizedMeshTile::convertUVHToLonLatHeight( const unsigned short &u, const unsigned short &v, const unsigned short &h, 29 | double &lon, double &lat, double &height ) const 30 | { 31 | const ctb::GlobalGeodetic profile; 32 | const ctb::CRSBounds tileBounds = profile.tileBounds(*this); 33 | const Header header = getHeader() ; 34 | 35 | lon = tileBounds.getMinX() + fabs( tileBounds.getMaxX() - tileBounds.getMinX() ) * (double)u/(double)QuantizedMesh::MAX_VERTEX_DATA ; 36 | lat = tileBounds.getMinY() + fabs( tileBounds.getMaxY() - tileBounds.getMinY() ) * (double)v/(double)QuantizedMesh::MAX_VERTEX_DATA ; 37 | height = header.MinimumHeight + fabs( header.MaximumHeight - header.MinimumHeight ) * (double)h/(double)QuantizedMesh::MAX_VERTEX_DATA ; 38 | } 39 | 40 | 41 | 42 | bool QuantizedMeshTile::exportToOFF( const std::string &outFilePath, const bool& useRealWorldValues ) 43 | { 44 | std::ofstream of( outFilePath.c_str(), std::ios_base::out ) ; 45 | if (!of.is_open()) 46 | return false ; 47 | 48 | // Magic header 49 | of << "OFF" << std::endl ; 50 | 51 | IndexData indexData = this->getIndexData() ; 52 | VertexData vertexData = this->getVertexData() ; 53 | 54 | // Number of vertices and triangles (0 edges, not really used in the format...) 55 | of << vertexData.vertexCount << " " << indexData.triangleCount << " 0" << std::endl ; 56 | 57 | // Vertices 58 | for ( int i = 0; i < vertexData.vertexCount; i++ ) 59 | { 60 | // Convert to Lon/Lat/Height real values from U/V/Height stored in the quantized mesh 61 | if (useRealWorldValues) { 62 | double lon, lat, height; 63 | convertUVHToLonLatHeight(vertexData.u[i], vertexData.v[i], vertexData.height[i], lon, lat, height); 64 | of << lon << " " << lat << " " << height << std::endl; 65 | } 66 | else { 67 | of << vertexData.u[i] << " " << vertexData.v[i] << " " << vertexData.height[i] << std::endl; 68 | } 69 | } 70 | 71 | // Triangles 72 | of << "3 " ; 73 | for ( int i = 0; i < indexData.triangleCount*3; i++ ) 74 | { 75 | of << indexData.indices[i] << " "; 76 | 77 | if ( (i+1)%3 == 0 && i < (indexData.triangleCount*3)-1 ) 78 | of << std::endl << "3 " ; 79 | } 80 | 81 | return true ; 82 | } 83 | 84 | 85 | 86 | TinCreation::Point_3 QuantizedMeshTile::horizonOcclusionPoint( const std::vector &pts, const TinCreation::Point_3 ¢er ) 87 | { 88 | // Compute the scaledSpaceDirectionToPoint, a vector passing through the center of the ellipsoid and scaled on it 89 | // https://groups.google.com/forum/#!topic/cesium-dev/8NTW1Wl0d8s 90 | const double rX = m_ellipsoid.getRadiusX(); 91 | const double rY = m_ellipsoid.getRadiusY(); 92 | const double rZ = m_ellipsoid.getRadiusZ(); 93 | 94 | TinCreation::Vector_3 scaledSpaceDirectionToPoint = Vector_3( center.x()/rX, center.y()/rY, center.z()/rZ ) ; 95 | scaledSpaceDirectionToPoint = scaledSpaceDirectionToPoint / sqrt(scaledSpaceDirectionToPoint.squared_length()) ; // Normalize 96 | 97 | std::vector< TinCreation::Point_3 >::const_iterator it ; 98 | double maxMagnitude = 0 ; 99 | for ( it = pts.begin(); it != pts.end(); ++it ) { 100 | double magnitude = computeHorizonOcclusionPointMagnitude( *it, scaledSpaceDirectionToPoint ) ; 101 | if ( magnitude > maxMagnitude ) 102 | maxMagnitude = magnitude ; 103 | } 104 | 105 | TinCreation::Vector_3 hov = scaledSpaceDirectionToPoint * maxMagnitude ; 106 | 107 | return TinCreation::Point_3( hov.x(), hov.y(), hov.z() ) ; 108 | } 109 | 110 | 111 | 112 | double QuantizedMeshTile::computeHorizonOcclusionPointMagnitude( const TinCreation::Point_3 &position, const TinCreation::Vector_3 &scaledSpaceDirectionToPoint ) 113 | { 114 | const double rX = m_ellipsoid.getRadiusX(); 115 | const double rY = m_ellipsoid.getRadiusY(); 116 | const double rZ = m_ellipsoid.getRadiusZ(); 117 | 118 | TinCreation::Vector_3 scaledSpaceVector( position.x()/rX, position.y()/rY, position.z()/rZ ) ; 119 | 120 | double magnitudeSquared = scaledSpaceVector.squared_length(); 121 | double magnitude = sqrt(magnitudeSquared); 122 | TinCreation::Vector_3 unitScaledSpaceVector = scaledSpaceVector / magnitude ; 123 | 124 | // For the purpose of this computation, points below the ellipsoid 125 | // are considered to be on it instead. 126 | magnitudeSquared = std::max(1.0, magnitudeSquared); 127 | magnitude = std::max(1.0, magnitude); 128 | 129 | double cosAlpha = unitScaledSpaceVector * scaledSpaceDirectionToPoint ; 130 | double sinAlpha = sqrt( CGAL::cross_product( unitScaledSpaceVector, scaledSpaceDirectionToPoint ).squared_length() ); 131 | double cosBeta = 1.0 / magnitude; 132 | double sinBeta = sqrt(magnitudeSquared - 1.0) * cosBeta ; 133 | 134 | return 1.0 / (cosAlpha * cosBeta - sinAlpha * sinBeta); 135 | } -------------------------------------------------------------------------------- /src/base/quantized_mesh_tile.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Coronis Computing S.L. (Spain) 2 | // All rights reserved. 3 | // 4 | // This file is part of EMODnet Quantized Mesh Generator for Cesium. 5 | // 6 | // This program is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | // Author: Ricard Campos (ricardcd@gmail.com) 20 | 21 | #ifndef EMODNET_QMGC_QUANTIZED_MESH_TILE_H 22 | #define EMODNET_QMGC_QUANTIZED_MESH_TILE_H 23 | 24 | #include "quantized_mesh.h" 25 | #include "ellipsoid.h" 26 | #include "tin_creation/tin_creation_cgal_types.h" 27 | 28 | 29 | /** 30 | * @class QuantizedMeshTile 31 | * @brief Encapsulates a Tile in Quantized Mesh format * 32 | */ 33 | class QuantizedMeshTile : 34 | public QuantizedMesh, public ctb::Tile 35 | { 36 | friend class TerrainTiler; 37 | friend class QuantizedMeshTiler; 38 | 39 | public: 40 | // --- Typedefs --- 41 | typedef TinCreation::Point_3 Point_3 ; 42 | typedef TinCreation::Vector_3 Vector_3 ; 43 | 44 | /** 45 | * @brief Creates a quantized mesh tile from a tile coordinate 46 | * @param coord Coordinates of the tile 47 | * @param e The reference Ellipsoid to use 48 | */ 49 | QuantizedMeshTile(const ctb::TileCoordinate &coord, 50 | const Ellipsoid& e = WGS84Ellipsoid()) 51 | : QuantizedMesh() 52 | , Tile(coord) 53 | , m_ellipsoid(e) {} 54 | 55 | /** 56 | * @brief Create a quantized mesh tile from a file 57 | * @param fileName The quantized-mesh tile file 58 | * @param coord Coordinates of the tile 59 | * @param e The reference Ellipsoid to use 60 | */ 61 | QuantizedMeshTile(const char *fileName, 62 | const ctb::TileCoordinate &coord, 63 | const Ellipsoid& e = WGS84Ellipsoid()) 64 | : QuantizedMesh(fileName) 65 | , Tile(coord) 66 | , m_ellipsoid(e) {} 67 | 68 | /** 69 | * @brief Creates a quantized mesh tile from quantized mesh data 70 | * @param qm QuantizedMesh data 71 | * @param coord Coordinates of the tile 72 | * @param e The reference Ellipsoid to use 73 | */ 74 | QuantizedMeshTile(const QuantizedMesh &qm, 75 | const ctb::TileCoordinate &coord, 76 | const Ellipsoid& e = WGS84Ellipsoid()) 77 | : QuantizedMesh(qm) 78 | , Tile(coord) 79 | , m_ellipsoid(e) {} 80 | 81 | /// Convert U/V/Height coordinates in quantized mesh tile to Lon/Lat/Height 82 | void convertUVHToLonLatHeight( const unsigned short &u, const unsigned short &v, const unsigned short &h, 83 | double &lon, double &lat, double &height ) const ; 84 | 85 | /** 86 | * @brief Exports the geometry of the tile to OFF format 87 | * @param outFilePath Output file path 88 | * @param useRealWorldValues Flag indicating whether the vertices of the output geometry are the real values (i.e., the lat/lon/height coordinates) or the quantized values. 89 | * @return True if file created successfully. 90 | */ 91 | bool exportToOFF( const std::string &outFilePath, const bool& useRealWorldValues = false ) ; 92 | 93 | /** 94 | * @brief Compute the horizon occlusion point for the given tile 95 | * @param pts Vertices of the tile (in ECEF coordinates!) 96 | * @param center Centroid of the tile 97 | * @return Horizon occlusion point 98 | */ 99 | Point_3 horizonOcclusionPoint( const std::vector &pts, const Point_3 ¢er ) ; 100 | 101 | private: 102 | // Function as described in https://cesium.com/blog/2013/05/09/computing-the-horizon-occlusion-point/ 103 | // We ommit the ellipsoid here for simplicity (hard-coded) 104 | double computeHorizonOcclusionPointMagnitude( const Point_3 &position, const Vector_3 &scaledSpaceDirectionToPoint ) ; 105 | 106 | // --- Attributes --- 107 | Ellipsoid m_ellipsoid ; //!< The reference ellipsoid 108 | }; 109 | 110 | #endif //EMODNET_QMGC_QUANTIZED_MESH_TILE_H 111 | -------------------------------------------------------------------------------- /src/base/quantized_mesh_tiles_pyramid_builder.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Coronis Computing S.L. (Spain) 2 | // All rights reserved. 3 | // 4 | // This file is part of EMODnet Quantized Mesh Generator for Cesium. 5 | // 6 | // This program is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | // Author: Ricard Campos (ricardcd@gmail.com) 20 | 21 | #ifndef EMODNET_QMGC_QUANTIZED_MESH_TILES_PYRAMID_BUILDER_H 22 | #define EMODNET_QMGC_QUANTIZED_MESH_TILES_PYRAMID_BUILDER_H 23 | 24 | #include 25 | #include "tin_creation/tin_creation_cgal_types.h" 26 | #include "quantized_mesh_tiler.h" 27 | #include "zoom_tiles_scheduler.h" 28 | #include "zoom_tiles_border_vertices_cache.h" 29 | #include 30 | #include 31 | #include 32 | #include "borders_data.h" 33 | 34 | 35 | 36 | /** 37 | * @class QuantizedMeshTilesPyramidBuilder 38 | * @brief Contains the logic to create the pyramid of tiles in quantized mesh format. 39 | * 40 | * Since the quantized mesh format requires coherence between neighboring tiles, this class is the responsible 41 | * of maintaining this coherence and schedule the building of tiles by taking into account the ones already built. 42 | */ 43 | class QuantizedMeshTilesPyramidBuilder 44 | { 45 | // --- Private typedefs --- 46 | typedef typename TinCreation::Point_3 Point_3; 47 | 48 | public: 49 | 50 | /** 51 | * Constructor 52 | * @param qmTilers Vector of tilers, one for each desired thread (they should be the same!) 53 | * @param scheduler The desired scheduler defining a preferred order for processing the tiles 54 | */ 55 | QuantizedMeshTilesPyramidBuilder(const std::vector& qmTilers, 56 | const ZoomTilesScheduler& scheduler); 57 | 58 | /** 59 | * @brief Creates the tile pyramid in quantized-mesh format 60 | * 61 | * Due to the quantized-mesh format requiring the vertices on the edges to coincide between neighbors, the creation 62 | * of the tiles' for each zoom is not as simple as in the heightmap format, and it requires a more complex loop taking 63 | * into account vertices at borders of the neighbors of the current tile being processed 64 | */ 65 | void createTmsPyramid(const int &startZoom, const int &endZoom, const std::string &outDir, const std::string &debugDir = std::string("")) ; 66 | 67 | /** 68 | * @brief Creates the tile pyramid in quantized-mesh format without taking into account coherence along neighboring tiles' borders 69 | * Useful when we know, by the way the simplification is created, that the vertices in the borders will always be the same (e.g., in the Delaunay TIN creation strategy) 70 | */ 71 | void createTmsPyramidUnconstrainedBorders(const int &startZoom, const int &endZoom, const std::string &outDir, const std::string &debugDir = std::string("")) ; 72 | 73 | /** 74 | * @brief Check if the tile folder (zoom/x) exists, and creates it otherwise. 75 | * 76 | * @return The path of the tile's file. 77 | */ 78 | static std::string getTileFileAndCreateDirs( const ctb::TileCoordinate &coord, 79 | const std::string &mainOutDir ) ; 80 | 81 | /** 82 | * @brief Create the required tile, in the given thread, and with the given data at the borders to maintain. 83 | * The result is an output tile file created, and an updated BorderData structure with the data to maintain for neighboring tiles to be created. 84 | * @param coord The tile coordinates 85 | * @param numThread The thread number where the process will take place 86 | * @param outDir The output directory where the output tile file will be generated 87 | * @param bd The BordersData structure input. It contains the data to preserve at the borders as a result of previously generated tiles. 88 | * @return It returns the data at the borders to be maintained for neighboring tiles to be generated in the future (i.e., what was already restricted in \p bd, plus the new borders created). 89 | */ 90 | BordersData createTile( const ctb::TileCoordinate& coord, 91 | const int& numThread, 92 | const std::string& outDir, 93 | const BordersData& bd ) ; 94 | 95 | /** 96 | * Get the next tile to process in the current zoom 97 | * @param tileXY The (x,y) coordinates of the tile to process within the current zoom 98 | * @return Returns true if a tile to be processed was located in the queue, false otherwise 99 | */ 100 | bool getNextTileToProcess(ctb::TilePoint& tileXY) ; 101 | 102 | private: 103 | // --- Attributes --- 104 | int m_numThreads ; 105 | std::vector m_tilers ; 106 | ZoomTilesScheduler m_scheduler ; 107 | std::vector m_tilesWaitingToProcess ; 108 | ZoomTilesBorderVerticesCache m_bordersCache ; 109 | bool m_debugMode ; 110 | std::string m_debugDir ; 111 | std::mutex m_diskWriteMutex; 112 | 113 | /** 114 | * @brief Check that the DEBUG tile folder (zoom/x) exists, and creates it otherwise. 115 | * 116 | * @return The path of the debug OFF tile's file. 117 | */ 118 | std::string getDebugTileFileAndCreateDirs( const ctb::TileCoordinate &coord ) ; 119 | 120 | }; 121 | 122 | 123 | #endif //EMODNET_QMGC_QUANTIZED_MESH_TILES_PYRAMID_BUILDER_H 124 | -------------------------------------------------------------------------------- /src/base/tile_border_vertices.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Coronis Computing S.L. (Spain) 2 | // All rights reserved. 3 | // 4 | // This file is part of EMODnet Quantized Mesh Generator for Cesium. 5 | // 6 | // This program is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | // Author: Ricard Campos (ricardcd@gmail.com) 20 | 21 | #ifndef EMODNET_QMGC_TILE_BORDER_VERTICES_H 22 | #define EMODNET_QMGC_TILE_BORDER_VERTICES_H 23 | 24 | #include "tin_creation/tin_creation_cgal_types.h" 25 | #include 26 | 27 | 28 | /** 29 | * @struct BorderVertex 30 | * @brief Class storing a vertex on the border of a tile 31 | * 32 | * Since for the border vertices one of the coordinates can be deduced depending on which border vertex they are, we 33 | * just store the variable coordinate and the height measure 34 | */ 35 | struct BorderVertex { 36 | double coord ; 37 | double height ; 38 | 39 | BorderVertex( const double& c, const double& h ) : coord(c), height(h) {} 40 | 41 | // To be able to sort the vertices by coordinates 42 | bool operator < (const BorderVertex& v) const 43 | { 44 | return (coord < v.coord); 45 | } 46 | }; 47 | 48 | 49 | /** 50 | * @class TileBorderVertices 51 | * @brief Stores the vertices on the borders of a tile. 52 | */ 53 | class TileBorderVertices 54 | { 55 | public: 56 | TileBorderVertices() 57 | : m_easternVertices() 58 | , m_westernVertices() 59 | , m_northernVertices() 60 | , m_southernVertices() 61 | , m_lifeCounter(0) {} 62 | 63 | TileBorderVertices( const std::vector& easternVertices, 64 | const std::vector& westernVertices, 65 | const std::vector& northernVertices, 66 | const std::vector& southernVertices, 67 | const int& lifeCounter = 4 ) // The life counter will be 4 for those tiles not in the zoom borders and surrounded by unprocessed tiles 68 | : m_easternVertices(easternVertices) 69 | , m_westernVertices(westernVertices) 70 | , m_northernVertices(northernVertices) 71 | , m_southernVertices(southernVertices) 72 | , m_lifeCounter(lifeCounter) {} 73 | 74 | // Each time we consult for a border, we update the number of times it has been consulted by decreasing the lifeCounter. 75 | // When it gets to zero, the information in this object will not be needed anymore and can be deleted (responsability of the cache object) 76 | std::vector getEasternVerticesAndDecreaseLife() { m_lifeCounter-- ; return m_easternVertices ; } 77 | std::vector getWesternVerticesAndDecreaseLife() { m_lifeCounter-- ; return m_westernVertices ; } 78 | std::vector getNorthernVerticesAndDecreaseLife() { m_lifeCounter-- ; return m_northernVertices ; } 79 | std::vector getSouthernVerticesAndDecreaseLife() { m_lifeCounter-- ; return m_southernVertices ; } 80 | 81 | std::vector getEasternVertices() { return m_easternVertices ; } 82 | std::vector getWesternVertices() { return m_westernVertices ; } 83 | std::vector getNorthernVertices() { return m_northernVertices ; } 84 | std::vector getSouthernVertices() { return m_southernVertices ; } 85 | 86 | void decreaseLife() { m_lifeCounter--; } 87 | 88 | bool isAlive() { return m_lifeCounter > 0 ; } 89 | 90 | private: 91 | std::vector m_easternVertices ; 92 | std::vector m_westernVertices ; 93 | std::vector m_northernVertices ; 94 | std::vector m_southernVertices ; 95 | int m_lifeCounter ; 96 | }; 97 | 98 | #endif //EMODNET_QMGC_TILE_BORDER_VERTICES_H 99 | -------------------------------------------------------------------------------- /src/cgal/border_edges_are_constrained_edge_map.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Coronis Computing S.L. (Spain) 2 | // All rights reserved. 3 | // 4 | // This file is part of EMODnet Quantized Mesh Generator for Cesium. 5 | // 6 | // This program is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | // Author: Ricard Campos (ricardcd@gmail.com) 20 | 21 | #ifndef EMODNET_QMGC_CGAL_SIMPLIFICATION_CONSTRAINED_BORDERS_H 22 | #define EMODNET_QMGC_CGAL_SIMPLIFICATION_CONSTRAINED_BORDERS_H 23 | 24 | #include "tin_creation/tin_creation_cgal_types.h" 25 | #include "cgal_utils.h" 26 | 27 | 28 | /** 29 | * @class BorderEdgesAreConstrainedEdgeMap 30 | * 31 | * @brief BGL property map indicating whether an edge is marked as non-removable 32 | * 33 | * We just need to mark as non-removable those edges corresponding to border edges of already processed neighboring tiles. 34 | */ 35 | template 36 | struct BorderEdgesAreConstrainedEdgeMap 37 | { 38 | typedef typename boost::graph_traits::edge_descriptor key_type ; 39 | typedef bool value_type ; 40 | typedef value_type reference ; 41 | typedef boost::readable_property_map_tag category; 42 | typedef typename Polyhedron::Point_3 Point_3; 43 | 44 | const Polyhedron* m_pPolyPtr ; 45 | const bool m_constrainEastBorder ; 46 | const bool m_constrainWestBorder ; 47 | const bool m_constrainNorthBorder ; 48 | const bool m_constrainSouthBorder ; 49 | 50 | BorderEdgesAreConstrainedEdgeMap( const Polyhedron& sm, 51 | const bool& constrainEastBorder = true, 52 | const bool& constrainWestBorder = true, 53 | const bool& constrainNorthBorder = true, 54 | const bool& constrainSouthBorder = true ) 55 | : m_pPolyPtr(&sm) 56 | , m_constrainEastBorder(constrainEastBorder) 57 | , m_constrainWestBorder(constrainWestBorder) 58 | , m_constrainNorthBorder(constrainNorthBorder) 59 | , m_constrainSouthBorder(constrainSouthBorder) {} 60 | 61 | friend bool get(BorderEdgesAreConstrainedEdgeMap m, const key_type& edge) 62 | { 63 | bool isBorder = CGAL::is_border(edge, *m.m_pPolyPtr); 64 | if (isBorder) { 65 | Point_3 p0 = edge.halfedge()->vertex()->point() ; 66 | Point_3 p1 = edge.halfedge()->opposite()->vertex()->point() ; 67 | 68 | double diffX = fabs( p1.x() - p0.x() ) ; 69 | double diffY = fabs( p1.y() - p0.y() ) ; 70 | 71 | return ( m.m_constrainEastBorder && diffX < diffY && p0.x() > 0.5 ) || 72 | ( m.m_constrainWestBorder && diffX < diffY && p0.x() < 0.5 ) || 73 | ( m.m_constrainNorthBorder && diffY < diffX && p0.y() > 0.5 ) || 74 | ( m.m_constrainSouthBorder && diffY < diffX && p0.y() < 0.5 ) ; 75 | } 76 | else 77 | return false ; 78 | } 79 | }; 80 | 81 | #endif //EMODNET_QMGC_CGAL_SIMPLIFICATION_CONSTRAINED_BORDERS_H 82 | -------------------------------------------------------------------------------- /src/cgal/cgal_utils.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Coronis Computing S.L. (Spain) 2 | // All rights reserved. 3 | // 4 | // This file is part of EMODnet Quantized Mesh Generator for Cesium. 5 | // 6 | // This program is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | // Author: Ricard Campos (ricardcd@gmail.com) 20 | 21 | #ifndef EMODNET_QMGC_CGAL_UTILS_H 22 | #define EMODNET_QMGC_CGAL_UTILS_H 23 | 24 | #include "tin_creation/tin_creation_cgal_types.h" 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | /** 32 | * @file 33 | * @brief Set of miscellaneous functions extending the functionality of the CGAL library 34 | */ 35 | 36 | /** 37 | * Checks if a given halfedge is incident to a corner vertex in the tile 38 | * Note that this check only works on our specific case... 39 | */ 40 | template 41 | bool isTileCorner( typename Polyhedron::Halfedge_const_handle e ) { 42 | typedef typename Polyhedron::Point_3 Point_3 ; 43 | 44 | if (e->is_border()) { 45 | Point_3 p0 = e->vertex()->point() ; // The vertex the halfedge is incident to 46 | Point_3 p1 = e->prev()->vertex()->point() ; // This is the previous vertex, with which p0 forms an edge 47 | 48 | // Differences between the points in the edge 49 | double diffX = fabs( p1.x() - p0.x() ) ; 50 | double diffY = fabs( p1.y() - p0.y() ) ; 51 | 52 | // Next edge on the border (since we are in a border halfedge, the next operator points to the next halfedge around the "hole" 53 | Point_3 p2 = e->next()->vertex()->point() ; 54 | 55 | // Differences between the points in the next edge 56 | double diffXNext = fabs( p2.x() - p0.x() ) ; 57 | double diffYNext = fabs( p2.y() - p0.y() ) ; 58 | 59 | // Compare slopes to see if e is incident to a corner vertex (i.e., if p0 is a corner vertex) 60 | return ( ( diffX < diffY ) && ( diffXNext > diffYNext ) ) || 61 | ( ( diffX > diffY ) && ( diffXNext < diffYNext ) ) ; 62 | } 63 | else { 64 | return false ; 65 | } 66 | } 67 | 68 | 69 | 70 | /// Exports a 2D Delaunay on a 3D point set (i.e., using the Projection_traits_xy_3) to an OFF file, for debugging purposes 71 | template 72 | void delaunayToOFF( const std::string &outFilePath, const Delaunay &dt ) 73 | { 74 | std::ofstream ofs( outFilePath.c_str() ); 75 | ofs << "OFF\n" << dt.number_of_vertices() 76 | << " " << dt.number_of_faces() << " 0" << std::endl; 77 | 78 | std::map indices; 79 | int counter = 0; 80 | 81 | for(typename Delaunay::Finite_vertices_iterator it = dt.finite_vertices_begin(); it != dt.finite_vertices_end(); ++it) 82 | { 83 | ofs << it->point() << std::endl; 84 | indices.insert(std::pair(it, counter++)); 85 | } 86 | 87 | for(typename Delaunay::Finite_faces_iterator it = dt.finite_faces_begin(); it != dt.finite_faces_end(); ++it) 88 | { 89 | ofs << "3 " << indices[it->vertex(0)] 90 | << " " << indices[it->vertex(1)] 91 | << " " << indices[it->vertex(2)] << std::endl; 92 | } 93 | 94 | ofs.close() ; 95 | } 96 | 97 | 98 | 99 | /// Checks if a vertex in the polyhedron is in the border 100 | template 101 | bool isBorder(typename Polyhedron::Vertex_handle& v) 102 | { 103 | typename Polyhedron::Halfedge_around_vertex_const_circulator hv = v->vertex_begin(); 104 | //move around the vertex and check if there is a halfedge which 105 | //is on border 106 | do { 107 | if(hv->is_border()) 108 | return true; 109 | }while (++hv != v->vertex_begin()); 110 | return false; 111 | } 112 | 113 | 114 | /// Checks if a vertex in the polyhedron is in the border 115 | template 116 | bool isBorder(typename Polyhedron::Vertex_const_handle& v) 117 | { 118 | typename Polyhedron::Halfedge_around_vertex_const_circulator hv = v->vertex_begin(); 119 | //move around the vertex and check if there is a halfedge which 120 | //is on border 121 | do { 122 | if(hv->is_border()) 123 | return true; 124 | }while (++hv != v->vertex_begin()); 125 | return false; 126 | } 127 | 128 | 129 | 130 | /// Computes if a point \p query falls within the arc defined by the vectors \p p0 - \p center and \p p1 - \p center 131 | template 132 | bool isPointInArc( const typename K::Point_2& query, 133 | const typename K::Point_2& center, 134 | const typename K::Point_2& p0, 135 | const typename K::Point_2& p1 ) 136 | { 137 | typedef typename K::Vector_2 Vector_2; 138 | 139 | Vector_2 a = p0 - center ; 140 | Vector_2 b = query - center ; 141 | Vector_2 c = p1 - center ; 142 | 143 | double AxB = a.x()*b.y() - a.y()*b.x() ; 144 | double AxC = a.x()*c.y() - a.y()*c.x() ; 145 | double CxB = c.x()*b.y() - c.y()*b.x() ; 146 | double CxA = c.x()*a.y() - c.y()*a.x() ; 147 | 148 | return ( AxB*AxC >= 0. && CxB*CxA >= 0. ) ; 149 | } 150 | 151 | #endif //EMODNET_QMGC_CGAL_UTILS_H 152 | -------------------------------------------------------------------------------- /src/cgal/corner_vertices_are_constrained_vertex_map.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Coronis Computing S.L. (Spain) 2 | // All rights reserved. 3 | // 4 | // This file is part of EMODnet Quantized Mesh Generator for Cesium. 5 | // 6 | // This program is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | // Author: Ricard Campos (ricardcd@gmail.com) 20 | 21 | #ifndef EMODNET_QMGC_CORNER_VERTICES_ARE_CONSTRAINED_VERTEX_MAP_H 22 | #define EMODNET_QMGC_CORNER_VERTICES_ARE_CONSTRAINED_VERTEX_MAP_H 23 | 24 | #include "tin_creation/tin_creation_cgal_types.h" 25 | #include "cgal_utils.h" 26 | #include 27 | 28 | 29 | /** 30 | * @struct CornerVerticesAreConstrainedVertexMap 31 | * 32 | * @brief BGL property map indicating whether a given vertex is one of the 4 corners of the tile. 33 | * 34 | * We need to preserve these corners when simplifying a tile. 35 | */ 36 | template 37 | struct CornerVerticesAreConstrainedVertexMap 38 | { 39 | typedef typename boost::graph_traits::vertex_descriptor key_type; 40 | typedef typename boost::graph_traits::halfedge_descriptor HalfedgeDescriptor; 41 | typedef bool value_type; 42 | typedef value_type reference; 43 | typedef typename Polyhedron::Point_3 Point_3; 44 | 45 | const Polyhedron *m_pPolyPtr; 46 | 47 | CornerVerticesAreConstrainedVertexMap( const Polyhedron &sm ) : m_pPolyPtr(&sm) {} 48 | 49 | friend bool get(CornerVerticesAreConstrainedVertexMap m, const key_type &vertex) 50 | { 51 | // The vertex must be on the border 52 | boost::optional he = CGAL::is_border( vertex, *m.m_pPolyPtr ) ; 53 | 54 | if (he) { 55 | // Next edge on the border (since we are in a border halfedge, the next operator should point to the next halfedge around the "hole") 56 | if ( (*he)->next()->is_border() ) { 57 | // Check the differences in X and Y to discern if this is a corner vertex 58 | 59 | // Relevant geometric info of the current edge 60 | Point_3 p0 = vertex->point() ; 61 | Point_3 p1 = (*he)->opposite()->vertex()->point() ; // This is the previous vertex, with which p0 forms an edge 62 | 63 | // Differences between the points in the edge 64 | double diffX = fabs( p1.x() - p0.x() ) ; 65 | double diffY = fabs( p1.y() - p0.y() ) ; 66 | 67 | Point_3 p2 = (*he)->next()->vertex()->point() ; 68 | 69 | double diffXNext = fabs( p2.x() - p0.x() ) ; 70 | double diffYNext = fabs( p2.y() - p0.y() ) ; 71 | 72 | return ( ( diffX < diffY ) && ( diffXNext > diffYNext ) ) || 73 | ( ( diffX > diffY ) && ( diffXNext < diffYNext ) ) ; 74 | } 75 | else { 76 | return false ; 77 | } 78 | } 79 | else { 80 | return false ; 81 | } 82 | } 83 | }; 84 | 85 | #endif // EMODNET_QMGC_CORNER_VERTICES_ARE_CONSTRAINED_VERTEX_MAP_H 86 | -------------------------------------------------------------------------------- /src/cgal/detect_sharp_edges_without_borders.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Coronis Computing S.L. (Spain) 2 | // All rights reserved. 3 | // 4 | // This file is part of EMODnet Quantized Mesh Generator for Cesium. 5 | // 6 | // This program is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | // Author: Ricard Campos (ricardcd@gmail.com) 20 | 21 | #ifndef EMODNET_QMGC_DETECT_SHARP_EDGES_WITHOUT_BORDERS_H 22 | #define EMODNET_QMGC_DETECT_SHARP_EDGES_WITHOUT_BORDERS_H 23 | 24 | #include 25 | #include 26 | 27 | /** 28 | * @brief Detects sharp edges in a polygon without accounting for the borders (the original implementation in CGAL considers the borders as feature edges, and we do not want that). 29 | * @tparam PolygonMesh Mesh type 30 | * @tparam FT Float type 31 | * @tparam EdgeIsSharpMap EdgeIsSharpMap type 32 | * @tparam GT Geometric traits 33 | * @param pmesh Polygon mesh 34 | * @param angle_in_deg Angle threshold to consider an edge as sharp 35 | * @param edge_is_sharp_map The output map where the detected sharp edges will be stored 36 | */ 37 | template 41 | void detect_sharp_edges_without_borders(PolygonMesh &pmesh, 42 | FT angle_in_deg, 43 | EdgeIsSharpMap &edge_is_sharp_map) { 44 | FT cos_angle(std::cos(CGAL::to_double(angle_in_deg) * CGAL_PI / 180.)); 45 | 46 | // Detect sharp edges 47 | BOOST_FOREACH(typename boost::graph_traits::edge_descriptor ed, edges(pmesh)) { 48 | typename boost::graph_traits::halfedge_descriptor he = halfedge(ed, pmesh); 49 | typedef typename boost::graph_traits::face_descriptor face_descriptor; 50 | 51 | // We skip border edges 52 | if (is_border_edge(he, pmesh)) 53 | continue; 54 | else { 55 | // Get the faces incident to this edge 56 | face_descriptor f1 = face(he, pmesh); 57 | face_descriptor f2 = face(opposite(he, pmesh), pmesh); 58 | 59 | // Compute their normal 60 | const typename GT::Vector_3 &n1 = CGAL::Polygon_mesh_processing::compute_face_normal(f1, pmesh); 61 | const typename GT::Vector_3 &n2 = CGAL::Polygon_mesh_processing::compute_face_normal(f2, pmesh); 62 | 63 | // Check the dihedral angle between them, and mark it as a sharp edge if it is larger than the threshold 64 | if (n1 * n2 <= cos_angle) { 65 | put(edge_is_sharp_map, edge(he, pmesh), true); 66 | } 67 | } 68 | } 69 | } 70 | 71 | #endif //EMODNET_QMGC_DETECT_SHARP_EDGES_WITHOUT_BORDERS_H 72 | -------------------------------------------------------------------------------- /src/cgal/extract_polylines_from_sharp_edges.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Coronis Computing S.L. (Spain) 2 | // All rights reserved. 3 | // 4 | // This file is part of EMODnet Quantized Mesh Generator for Cesium. 5 | // 6 | // This program is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | // Author: Ricard Campos (ricardcd@gmail.com) 20 | 21 | #ifndef EMODNET_QMGC_POLYLINES_FROM_FEATURED_EDGES_H 22 | #define EMODNET_QMGC_POLYLINES_FROM_FEATURED_EDGES_H 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | 30 | /** 31 | * @brief Struct/functor that returns true if the edge is sharp (given a previously computed edgeIsSharp map) 32 | * @tparam Surface_mesh 33 | * @tparam EdgeIsSharpMap 34 | */ 35 | template 36 | struct IsSharpEdge { 37 | typedef typename boost::graph_traits::edge_descriptor edge_descriptor; 38 | 39 | IsSharpEdge() {} // required by boost::filtered_graph 40 | 41 | IsSharpEdge(EdgeIsSharpMap eisMap) : m_eisMap(eisMap) {} 42 | 43 | bool operator()(typename boost::graph_traits::edge_descriptor e) const { 44 | return get(m_eisMap, e); 45 | } 46 | 47 | EdgeIsSharpMap m_eisMap; 48 | }; 49 | 50 | /** 51 | * @brief Visitor used by the extract_polylines_from_sharp_edges function 52 | * @tparam Graph 53 | * @tparam Polyline 54 | */ 55 | template 57 | struct ExtractPolylinesVisitor 58 | { 59 | std::vector& m_polylines; 60 | const Graph& m_graph; 61 | 62 | ExtractPolylinesVisitor(const Graph& graph, typename std::vector& polylines) 63 | : m_polylines(polylines), m_graph(graph) 64 | {} 65 | 66 | void start_new_polyline() 67 | { 68 | m_polylines.push_back(Polyline()); 69 | } 70 | 71 | void add_node(typename boost::graph_traits::vertex_descriptor vd) 72 | { 73 | if(m_polylines.back().empty()) { 74 | m_polylines.back().push_back(m_graph[vd]); 75 | } 76 | } 77 | 78 | void add_edge(typename boost::graph_traits::edge_descriptor ed) 79 | { 80 | typename boost::graph_traits::vertex_descriptor 81 | s = source(ed, m_graph), 82 | t = target(ed, m_graph); 83 | Polyline& polyline = m_polylines.back(); 84 | CGAL_assertion(!polyline.empty()); 85 | if(polyline.back() != m_graph[s]) { 86 | polyline.push_back(m_graph[s]); 87 | } else if(polyline.back() != m_graph[t]) { 88 | // if the edge is zero-length, it is ignored 89 | polyline.push_back(m_graph[t]); 90 | } 91 | } 92 | 93 | void end_polyline() 94 | { 95 | // ignore degenerated polylines 96 | if(m_polylines.back().size() < 2) 97 | m_polylines.resize(m_polylines.size() - 1); 98 | } 99 | }; 100 | 101 | /** 102 | * @brief Extracts polylines from a set of sharp edges in a surface mesh 103 | * @tparam Surface_mesh Surface mesh type 104 | * @tparam EdgeIsSharpMap EdgeIsSharpMap type 105 | * @tparam Polyline Polyline type 106 | * @param sm The input surface mesh 107 | * @param eisMap Map indicating wether an edge in the surface mesh is sharp or not 108 | * @param polylines The set of polylines extracted 109 | */ 110 | template 111 | void extract_polylines_from_sharp_edges(const Surface_mesh& sm, 112 | const EdgeIsSharpMap& eisMap, 113 | std::vector& polylines) 114 | { 115 | typedef typename boost::property_traits::type>::value_type Point_3; 116 | typedef boost::adjacency_list< 117 | boost::setS, // this avoids parallel edges 118 | boost::vecS, 119 | boost::undirectedS, 120 | Point_3 > Featured_edges_copy_graph; 121 | typedef IsSharpEdge IsSharpEdge; 122 | 123 | // Filter the "graph" (i.e., the mesh) using the created property map 124 | IsSharpEdge isSharpEdge(eisMap); 125 | typedef boost::filtered_graph FilteredGraph; 126 | FilteredGraph filteredGraph(sm, isSharpEdge); 127 | 128 | // Create a copy of the graph containing just the featured edges 129 | Featured_edges_copy_graph feGraph; 130 | typedef typename boost::property_map::const_type Vpm; 131 | Vpm vpm = get(CGAL::vertex_point, sm); 132 | 133 | typedef std::map::vertex_descriptor> P2vmap; 134 | P2vmap p2vmap; 135 | 136 | // --> Add vertices 137 | BOOST_FOREACH(typename FilteredGraph::vertex_descriptor v, vertices(filteredGraph)){ 138 | typename Featured_edges_copy_graph::vertex_descriptor vc; 139 | typename P2vmap::iterator it = p2vmap.find(get(vpm,v)); 140 | if(it == p2vmap.end()) { 141 | vc = add_vertex(feGraph); 142 | feGraph[vc] = get(vpm, v); 143 | p2vmap[get(vpm,v)] = vc; 144 | } 145 | } 146 | 147 | // --> Add edges 148 | BOOST_FOREACH(typename FilteredGraph::edge_descriptor e, edges(filteredGraph)) { 149 | typename Featured_edges_copy_graph::vertex_descriptor vs = p2vmap[get(vpm, source(e, filteredGraph))]; 150 | typename Featured_edges_copy_graph::vertex_descriptor vt = p2vmap[get(vpm, target(e, filteredGraph))]; 151 | CGAL_warning_msg(vs != vt, "ignore self loop"); 152 | if (vs != vt) { 153 | const std::pair pair = add_edge(vs, vt, feGraph); 154 | } 155 | } 156 | 157 | // Create the polylines 158 | ExtractPolylinesVisitor visitor(feGraph, polylines); 159 | CGAL::split_graph_into_polylines(feGraph, visitor); 160 | } 161 | 162 | 163 | #endif //EMODNET_QMGC_POLYLINES_FROM_FEATURED_EDGES_H 164 | -------------------------------------------------------------------------------- /src/cgal/extract_tile_borders_from_polyhedron.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Coronis Computing S.L. (Spain) 2 | // All rights reserved. 3 | // 4 | // This file is part of EMODnet Quantized Mesh Generator for Cesium. 5 | // 6 | // This program is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | // Author: Ricard Campos (ricardcd@gmail.com) 20 | 21 | #ifndef EMODNET_QMGC_CGAL_EXTRACT_TILE_BORDERS_FROM_POLYHEDRON_H 22 | #define EMODNET_QMGC_CGAL_EXTRACT_TILE_BORDERS_FROM_POLYHEDRON_H 23 | 24 | #include "tin_creation/tin_creation_cgal_types.h" 25 | #include 26 | 27 | 28 | 29 | /** 30 | * @brief Extracts the NSEW borders from a tile stored in Polyhedron form. 31 | * \pre We assume the outer border of the polygon when projected to the XY plane to have a square (or at least a rectangular) shape. 32 | * \pre normalize_borders() has been called before this function and is still valid 33 | */ 34 | template 35 | bool extractTileBordersFromPolyhedron(const Polyhedron& poly, 36 | std::vector& easternBorderPts, 37 | std::vector& westernBorderPts, 38 | std::vector& northernBorderPts, 39 | std::vector& southernBorderPts, 40 | typename Polyhedron::Point_3& cornerPoint00, 41 | typename Polyhedron::Point_3& cornerPoint01, 42 | typename Polyhedron::Point_3& cornerPoint10, 43 | typename Polyhedron::Point_3& cornerPoint11) 44 | { 45 | typedef typename Polyhedron::Point_3 Point_3; 46 | typedef typename Polyhedron::Traits::FT FT; 47 | typedef typename Polyhedron::Vertex_const_iterator Vertex_const_iterator; 48 | typedef typename Polyhedron::Halfedge_const_iterator Halfedge_const_iterator; 49 | 50 | easternBorderPts.clear(); 51 | westernBorderPts.clear(); 52 | northernBorderPts.clear(); 53 | southernBorderPts.clear(); 54 | 55 | int numCorners = 0 ; 56 | 57 | std::vector pts ; 58 | for ( Vertex_const_iterator it = poly.vertices_begin(); it != poly.vertices_end(); ++it ) 59 | pts.push_back(it->point()); 60 | Point_3 c3 = CGAL::centroid(pts.begin(), pts.end(),CGAL::Dimension_tag<0>()); 61 | FT midX = c3.x() ; 62 | FT midY = c3.y() ; 63 | 64 | Halfedge_const_iterator e = poly.border_halfedges_begin() ; 65 | ++e ; // We start at the second halfedge! 66 | while( e->is_border() ) 67 | { 68 | // Relevant geometric info of the current edge 69 | Point_3 p0 = e->vertex()->point() ; // This is the point we will take care of now 70 | Point_3 p1 = e->prev()->vertex()->point() ; // This is the previous vertex, with which p0 forms an edge 71 | 72 | // Differences between the points in the edge 73 | double diffX = fabs( p1.x() - p0.x() ) ; 74 | double diffY = fabs( p1.y() - p0.y() ) ; 75 | 76 | // Check if it is a corner point: the next vertex changes from vertical to horizontal or viceversa 77 | // If it is a corner point, we should add it twice to the corresponding border 78 | 79 | // Next edge on the border (since we are in a border halfedge, the next operator points to the next halfedge around the "hole" 80 | Point_3 p2 = e->next()->vertex()->point() ; 81 | 82 | double diffXNext = fabs( p2.x() - p0.x() ) ; 83 | double diffYNext = fabs( p2.y() - p0.y() ) ; 84 | bool isCorner = ( ( diffX < diffY ) && ( diffXNext > diffYNext ) ) || 85 | ( ( diffX > diffY ) && ( diffXNext < diffYNext ) ) ; 86 | 87 | if ( isCorner ) { 88 | numCorners++ ; 89 | if ( p0.x() < midX && p0.y() < midY ) { // Corner (0, 0) 90 | cornerPoint00 = p0; 91 | westernBorderPts.push_back(p0); 92 | southernBorderPts.push_back(p0); 93 | } 94 | else if ( p0.x() < midX && p0.y() > midY ) { // Corner (0, 1) 95 | cornerPoint01 = p0; 96 | westernBorderPts.push_back(p0); 97 | northernBorderPts.push_back(p0); 98 | } 99 | else if ( p0.x() > midX && p0.y() > midY ) { // Corner (1, 1) 100 | cornerPoint11 = p0; 101 | easternBorderPts.push_back(p0); 102 | northernBorderPts.push_back(p0); 103 | } 104 | else { // p0.x() > 0.5 && p0.y() < 0.5 ) // Corner (1, 0) 105 | cornerPoint10 = p0; 106 | easternBorderPts.push_back(p0); 107 | southernBorderPts.push_back(p0); 108 | } 109 | } 110 | else { 111 | if (diffX < diffY) { 112 | // Vertical edge, can be a western or eastern edge 113 | if (p0.x() < midX) { 114 | // Western border edge/vertex 115 | westernBorderPts.push_back(p0); 116 | } else { // p0.x() >= 0.5 117 | // Eastern border vertex 118 | easternBorderPts.push_back(p0); 119 | } 120 | } else { // diffX >= diffY 121 | // Horizontal edge, can be a northern or southern edge 122 | if (p0.y() < midY) { 123 | // Southern border edge/vertex 124 | southernBorderPts.push_back(p0); 125 | } else { // p0.y() >= 0.5 126 | // Northern border edge/vertex 127 | northernBorderPts.push_back(p0); 128 | } 129 | } 130 | } 131 | 132 | // Advance 2 positions (i.e., skip non-border halfedges) 133 | std::advance(e,2) ; 134 | } 135 | 136 | return numCorners == 4 ; 137 | } 138 | 139 | #endif //EMODNET_QMGC_CGAL_EXTRACT_TILE_BORDERS_FROM_POLYHEDRON_H 140 | -------------------------------------------------------------------------------- /src/cgal/further_constrained_placement.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Coronis Computing S.L. (Spain) 2 | // All rights reserved. 3 | // 4 | // This file is part of EMODnet Quantized Mesh Generator for Cesium. 5 | // 6 | // This program is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | // Author: Ricard Campos (ricardcd@gmail.com) 20 | 21 | /** 22 | * \brief Extension of CGAL's Constrained_placement class 23 | * 24 | * Extension of CGAL's Constrained_placement class in the CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Constrained_placement.h file. 25 | * The placement of the vertex resulting from a contraction of an edge containing a constrained vertex is that constrained vertex. 26 | * 27 | */ 28 | 29 | #ifndef EMODNET_QMGC_CGAL_FURTHER_CONSTRAINED_PLACEMENT_H 30 | #define EMODNET_QMGC_CGAL_FURTHER_CONSTRAINED_PLACEMENT_H 31 | 32 | #include 33 | #include 34 | #include 35 | 36 | 37 | 38 | namespace CGAL { 39 | 40 | namespace Surface_mesh_simplification { 41 | 42 | /** 43 | * @class FurtherConstrainedPlacement 44 | * 45 | * @brief Constrained placement class for CGAL::Surface_mesh_simplification, extending the normal constrained placement 46 | * to allow maintaining border vertices as well as corners in a tile 47 | */ 48 | template 49 | class FurtherConstrainedPlacement : public BasePlacement { 50 | public: 51 | 52 | EdgeIsConstrainedMap Edge_is_constrained_map; 53 | VertexIsConstrainedMap Vertex_is_constrained_map; 54 | 55 | public: 56 | FurtherConstrainedPlacement( 57 | EdgeIsConstrainedMap edgesMap = EdgeIsConstrainedMap(), 58 | VertexIsConstrainedMap vertMap = VertexIsConstrainedMap(), 59 | BasePlacement base = BasePlacement()) 60 | : BasePlacement(base), Edge_is_constrained_map(edgesMap), Vertex_is_constrained_map(vertMap) {} 61 | 62 | template 63 | optional operator()(Profile const &aProfile) const { 64 | typedef typename Profile::ECM ECM; 65 | typedef typename CGAL::Halfedge_around_target_iterator in_edge_iterator; 66 | 67 | // Constrained vertices 68 | bool isConstrainedV0 = get(Vertex_is_constrained_map, aProfile.v0()) ; 69 | bool isConstrainedV1 = get(Vertex_is_constrained_map, aProfile.v1()) ; 70 | 71 | if ( isConstrainedV0 && isConstrainedV1 ) { 72 | // Both vertices in the edge are constrained: the edge must remain as is, no placement possible 73 | return boost::optional(); 74 | } 75 | else if ( isConstrainedV0 ) { 76 | // v0 is constrained, return it as the placement 77 | typename Profile::Point p = get(aProfile.vertex_point_map(), aProfile.v0()) ; 78 | return get(aProfile.vertex_point_map(), aProfile.v0()) ; 79 | } 80 | else if ( isConstrainedV1 ) { 81 | // v1 is constrained, return it as the placement 82 | typename Profile::Point p = get(aProfile.vertex_point_map(), aProfile.v1()) ; 83 | return get(aProfile.vertex_point_map(), aProfile.v1()) ; 84 | } 85 | 86 | // Constrained edges 87 | in_edge_iterator eb, ee; 88 | for (boost::tie(eb, ee) = halfedges_around_target(aProfile.v0(), aProfile.surface_mesh()); 89 | eb != ee; ++eb) { 90 | if (get(Edge_is_constrained_map, edge(*eb, aProfile.surface_mesh()))) 91 | return get(aProfile.vertex_point_map(), 92 | aProfile.v0()); 93 | } 94 | for (boost::tie(eb, ee) = halfedges_around_target(aProfile.v1(), aProfile.surface_mesh()); 95 | eb != ee; ++eb) { 96 | if (get(Edge_is_constrained_map, edge(*eb, aProfile.surface_mesh()))) 97 | return get(aProfile.vertex_point_map(), 98 | aProfile.v1()); 99 | } 100 | 101 | return static_cast(this)->operator()(aProfile); 102 | } 103 | }; 104 | 105 | } 106 | } 107 | #endif //EMODNET_QMGC_CGAL_FURTHER_CONSTRAINED_PLACEMENT_H 108 | -------------------------------------------------------------------------------- /src/cgal/generate_border_features_polylines.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Coronis Computing S.L. (Spain) 2 | // All rights reserved. 3 | // 4 | // This file is part of EMODnet Quantized Mesh Generator for Cesium. 5 | // 6 | // This program is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | // Author: Ricard Campos (ricardcd@gmail.com) 20 | 21 | #ifndef EMODNET_QMGC_GENERATE_BORDER_FEATURES_POLYLINES_H 22 | #define EMODNET_QMGC_GENERATE_BORDER_FEATURES_POLYLINES_H 23 | 24 | #include "tin_creation/tin_creation_cgal_types.h" 25 | #include "cgal_utils.h" 26 | #include 27 | 28 | /** 29 | * @brief Gets the polylines corresponding to the edges on each of the 4 borders the tile if the corresponding flag 30 | * constrainBorder is set. If not set, the polyline is a line going from 0 to 1. 31 | * 32 | * @pre The normalize_border() function must have been called on @param surface before running this function 33 | * @param surface 34 | * @param constrainEastBorder 35 | * @param constrainWestBorder 36 | * @param constrainNorthBorder 37 | * @param constrainSouthBorder 38 | */ 39 | template 40 | std::vector> 41 | generateBorderFeaturesPolylines( const Polyhedron& surface, 42 | const bool& constrainEastBorder = true, 43 | const bool& constrainWestBorder = true, 44 | const bool& constrainNorthBorder = true, 45 | const bool& constrainSouthBorder = true ) 46 | { 47 | typedef typename Polyhedron::Point_3 Point_3; 48 | typedef typename Polyhedron::Traits::FT FT; 49 | typedef typename Polyhedron::Vertex_const_iterator Vertex_const_iterator; 50 | typedef std::vector Polyline; 51 | typedef std::vector Polylines; 52 | 53 | Polylines polylines ; 54 | 55 | // Compute the middle point for reference 56 | std::vector pts ; 57 | for ( Vertex_const_iterator it = surface.vertices_begin(); it != surface.vertices_end(); ++it ) 58 | pts.push_back(it->point()); 59 | Point_3 c3 = CGAL::centroid(pts.begin(), pts.end(),CGAL::Dimension_tag<0>()); 60 | FT midX = c3.x() ; 61 | FT midY = c3.y() ; 62 | 63 | // NOTE: The naming of the functions is a bit misleading in CGAL's documentation... 64 | // The docs always refer to border halfedges as those halfedges incident to the "hole". However, the range [border_halfedges_begin(), halfedges_end()) includes ALL halfedges in the border, those who are incident to the hole AND ALSO their opposites, incident on a face. 65 | // For this reason, we check if this is a real "border halfedge", and take the opposite if it is not 66 | typename Polyhedron::Halfedge_const_handle startHE = surface.border_halfedges_begin() ; 67 | if (!startHE->is_border()) 68 | startHE = startHE->opposite() ; 69 | typename Polyhedron::Halfedge_const_handle e = startHE ; 70 | 71 | Polyline plU; // Polyline for unconstrained border edges. This should be entered as a sequential polyline, not individual edges! 72 | bool prevIsRegularBorder = false ; // Checks wether the previously visited edge is a "regular" border edge, or it is a "constrained" border edge. When this is false, we should start a new polyline 73 | do { 74 | // Relevant geometric info of the current edge 75 | Point_3 p0 = e->vertex()->point() ; // This is the point we will take care of now 76 | Point_3 p1 = e->prev()->vertex()->point() ; // This is the previous vertex, with which p0 forms an edge 77 | 78 | double diffX = fabs( p1.x() - p0.x() ) ; 79 | double diffY = fabs( p1.y() - p0.y() ) ; 80 | 81 | if ( ( constrainEastBorder && diffX < diffY && p0.x() > midX ) || 82 | ( constrainWestBorder && diffX < diffY && p0.x() < midX ) || 83 | ( constrainNorthBorder && diffY < diffX && p0.y() > midY ) || 84 | ( constrainSouthBorder && diffY < diffX && p0.y() < midY ) ) { 85 | // We add this edge as a polyline, since polylines' endpoints are preserved by the meshing algorithm 86 | Polyline pl; 87 | pl.push_back(p0); 88 | pl.push_back(p1); 89 | 90 | polylines.push_back(pl); 91 | prevIsRegularBorder = false; 92 | } 93 | else { 94 | // The edge is a border edge, so we must constrain it to remain in the mesh, but we don't fix its vertices 95 | if (!prevIsRegularBorder) { 96 | if (!plU.empty()) 97 | polylines.push_back(plU); 98 | plU.clear() ; 99 | plU.push_back(p1) ; 100 | plU.push_back(p0) ; 101 | prevIsRegularBorder = true ; 102 | } 103 | else { 104 | plU.push_back(p0); 105 | } 106 | } 107 | 108 | if (prevIsRegularBorder) 109 | // If the edge is regular so far, check if it is incident to a corner (they need to be endpoints of the polylines to be maintained during meshing) 110 | prevIsRegularBorder = !isTileCorner(e) ; 111 | 112 | e = e->next() ; // Advancing in this way should circulate through the "hole", if we start in a border halfedge 113 | } 114 | while ( e != startHE ); // Finish when we reach the starting point 115 | 116 | if (!plU.empty()) 117 | polylines.push_back(plU) ; 118 | 119 | return polylines ; 120 | } 121 | 122 | #endif //EMODNET_QMGC_GENERATE_BORDER_FEATURES_POLYLINES_H 123 | -------------------------------------------------------------------------------- /src/cgal/legacy/Polyhedral_mesh_domain_with_features_3_extended.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Coronis Computing S.L. (Spain) 2 | // All rights reserved. 3 | // 4 | // This file is part of EMODnet Quantized Mesh Generator for Cesium. 5 | // 6 | // This program is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | // Author: Ricard Campos (ricardcd@gmail.com) 20 | 21 | #ifndef EMODNET_QMGC_POLYHEDRAL_MESH_DOMAIN_WITH_FEATURES_3_EXTENDED_H 22 | #define EMODNET_QMGC_POLYHEDRAL_MESH_DOMAIN_WITH_FEATURES_3_EXTENDED_H 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include "polyhedron_detect_sharp_features.h" 29 | 30 | namespace CGAL { 31 | 32 | /** 33 | * @class Polyhedral_mesh_domain_with_features_3_extended 34 | * 35 | * 36 | */ 37 | template::type, 39 | class TriangleAccessor=Triangle_accessor_3, 40 | class Use_patch_id_tag = Tag_true, 41 | class Use_exact_intersection_construction_tag = Tag_true> 42 | class Polyhedral_mesh_domain_with_features_3_extended 43 | : public Polyhedral_mesh_domain_with_features_3 44 | { 45 | typedef Polyhedral_mesh_domain_with_features_3 Base; 46 | 47 | typedef Polyhedron_ Polyhedron; 48 | 49 | public: 50 | // Index types 51 | typedef typename Base::Index Index; 52 | typedef typename Base::Corner_index Corner_index; 53 | typedef typename Base::Curve_segment_index Curve_segment_index; 54 | typedef typename Base::Surface_patch_index Surface_patch_index; 55 | typedef typename Base::Subdomain_index Subdomain_index; 56 | 57 | // Backward compatibility 58 | #ifndef CGAL_MESH_3_NO_DEPRECATED_SURFACE_INDEX 59 | typedef Surface_patch_index Surface_index; 60 | #endif // CGAL_MESH_3_NO_DEPRECATED_SURFACE_INDEX 61 | 62 | typedef typename Base::R R; 63 | typedef typename Base::Point_3 Point_3; 64 | typedef typename Base::FT FT; 65 | 66 | typedef CGAL::Tag_true Has_features; 67 | 68 | // New typedefs 69 | typedef std::vector Polyline; 70 | typedef std::vector Polylines; 71 | 72 | template 73 | Polyhedral_mesh_domain_with_features_3_extended(InputPolyhedraPtrIterator begin, 74 | InputPolyhedraPtrIterator end, 75 | CGAL::Random* p_rng = NULL) 76 | : Base(begin, end, p_rng) {} 77 | 78 | Polylines extract_features_without_borders(FT angle_in_degree, Polyhedron&p) { 79 | // for (std::size_t i = 0; i < polys.size(); ++i) { 80 | // Polyhedron &p = polys[i]; 81 | this->initialize_ts(p); 82 | 83 | // Get sharp features 84 | // Mesh_3::detect_features(p, angle_in_degree); 85 | detect_sharp_edges(p, angle_in_degree); 86 | 87 | // Get polylines 88 | typedef Mesh_3::Polyline_with_context PolylineWithContext; 90 | 91 | std::vector polylinesWithContext; 92 | typedef std::back_insert_iterator > Output_iterator; 93 | 94 | Mesh_3::detect_polylines( 95 | &p, std::back_inserter(polylinesWithContext)); 96 | 97 | // Insert polylines in domain 98 | Mesh_3::Extract_bare_polyline extractor; 99 | 100 | Polylines polylines; 101 | polylines.insert(polylines.end(), 102 | boost::make_transform_iterator(polylinesWithContext.begin(), extractor), 103 | boost::make_transform_iterator(polylinesWithContext.end(), extractor)); 104 | 105 | return polylines; 106 | // } 107 | } 108 | }; 109 | 110 | 111 | } // End namespace CGAL 112 | 113 | #endif //EMODNET_QMGC_POLYHEDRAL_MESH_DOMAIN_WITH_FEATURES_3_EXTENDED_H 114 | -------------------------------------------------------------------------------- /src/cgal/polyhedron_builder_from_projected_triangulation.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Coronis Computing S.L. (Spain) 2 | // All rights reserved. 3 | // 4 | // This file is part of EMODnet Quantized Mesh Generator for Cesium. 5 | // 6 | // This program is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | // Author: Ricard Campos (ricardcd@gmail.com) 20 | 21 | #ifndef EMODNET_QMGC_POLYHEDRON_BUILDER_FROM_PROJECTED_TRIANGULATION_H 22 | #define EMODNET_QMGC_POLYHEDRON_BUILDER_FROM_PROJECTED_TRIANGULATION_H 23 | 24 | /** 25 | * @class PolyhedronBuilderFromProjectedTriangulation 26 | * @brief A modifier creating a Polyhedron_3 structure with the incremental builder from a projected triangulation. 27 | * A "projected triangulation" is a Triangulation_2 with projection traits. That is, the triangulation was made on the plane, but the internal points are 3D. 28 | */ 29 | template 30 | class PolyhedronBuilderFromProjectedTriangulation : public CGAL::Modifier_base { 31 | public: 32 | typedef ProjectedTriangulation2 Tri; 33 | 34 | Tri m_dt ; 35 | 36 | PolyhedronBuilderFromProjectedTriangulation( const Tri &dt ) : m_dt(dt) {} 37 | 38 | void operator()( HDS& hds ) { 39 | typedef typename HDS::Vertex Vertex; 40 | typedef typename Vertex::Point Point; 41 | 42 | // Polyhedron_3 incremental builder 43 | CGAL::Polyhedron_incremental_builder_3 B( hds, true); 44 | B.begin_surface( m_dt.number_of_vertices(), m_dt.number_of_faces() ); 45 | 46 | std::map indices; 47 | int counter = 0 ; 48 | for(typename Tri::Finite_vertices_iterator it = m_dt.finite_vertices_begin(); 49 | it != m_dt.finite_vertices_end(); ++it) 50 | { 51 | B.add_vertex( it->point() ); 52 | indices.insert(std::pair(it, counter++)); 53 | } 54 | 55 | for(typename Tri::Finite_faces_iterator it = m_dt.finite_faces_begin(); 56 | it != m_dt.finite_faces_end(); ++it) 57 | { 58 | B.begin_facet(); 59 | B.add_vertex_to_facet( indices[it->vertex(0)] ); 60 | B.add_vertex_to_facet( indices[it->vertex(1)] ); 61 | B.add_vertex_to_facet( indices[it->vertex(2)] ); 62 | B.end_facet(); 63 | } 64 | 65 | // End the surface 66 | B.end_surface(); 67 | } 68 | }; 69 | 70 | 71 | #endif //EMODNET_QMGC_POLYHEDRON_BUILDER_FROM_PROJECTED_TRIANGULATION_H 72 | -------------------------------------------------------------------------------- /src/cgal/surface_mesh_from_projected_triangulation.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Coronis Computing S.L. (Spain) 2 | // All rights reserved. 3 | // 4 | // This file is part of EMODnet Quantized Mesh Generator for Cesium. 5 | // 6 | // This program is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | // Author: Ricard Campos (ricardcd@gmail.com) 20 | 21 | #ifndef EMODNET_QMGC_SURFACE_MESH_FROM_PROJECTED_TRIANGULATION_H 22 | #define EMODNET_QMGC_SURFACE_MESH_FROM_PROJECTED_TRIANGULATION_H 23 | 24 | #include 25 | 26 | /** 27 | * @brief Creates a SurfaceMesh from a projected triangulation. 28 | * A "projected triangulation" is a Triangulation_2 with projection traits. That is, the triangulation was made on the plane, but the internal points are 3D. 29 | */ 30 | template 31 | SurfaceMesh surfaceMeshFromProjectedTriangulation(const ProjectedTriangulation2& tri) 32 | { 33 | typedef ProjectedTriangulation2 Tri; 34 | typedef typename SurfaceMesh::vertex_index VertexIndex; 35 | SurfaceMesh sm; 36 | 37 | std::map indices; 38 | for(typename Tri::Finite_vertices_iterator it = tri.finite_vertices_begin(); 39 | it != tri.finite_vertices_end(); ++it) 40 | { 41 | VertexIndex vi = sm.add_vertex(it->point()); 42 | indices.insert(std::pair(it, vi)); 43 | } 44 | 45 | for(typename Tri::Finite_faces_iterator it = tri.finite_faces_begin(); 46 | it != tri.finite_faces_end(); ++it) 47 | { 48 | sm.add_face(indices[it->vertex(0)], indices[it->vertex(1)], indices[it->vertex(2)]); 49 | } 50 | 51 | return sm; 52 | } 53 | 54 | #endif //EMODNET_QMGC_SURFACE_MESH_FROM_PROJECTED_TRIANGULATION_H 55 | -------------------------------------------------------------------------------- /src/dev-tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(qm_parser qm_parser.cpp 2 | ../base/quantized_mesh_tile.cpp 3 | ../base/gzip_file_reader.cpp 4 | ../base/gzip_file_writer.cpp 5 | ../base/quantized_mesh.cpp) 6 | target_link_libraries(qm_parser ${Boost_LIBRARIES} ${ZLIB_LIBRARIES} ${CTB_LIBRARY} ${CGAL_LIBRARIES} ${GDAL_LIBRARY}) 7 | 8 | add_executable(test_read_write test_read_write.cpp 9 | ../base/quantized_mesh_tile.cpp 10 | ../base/gzip_file_reader.cpp 11 | ../base/gzip_file_writer.cpp 12 | ../base/quantized_mesh.cpp) 13 | target_link_libraries(test_read_write ${Boost_LIBRARIES} 14 | ${ZLIB_LIBRARIES} 15 | ${CTB_LIBRARY} 16 | ${CGAL_LIBRARIES} 17 | ${GDAL_LIBRARY}) 18 | 19 | add_executable(simplify_maintaining_border_edges simplify_preserving_border_edges.cpp) 20 | target_link_libraries(simplify_maintaining_border_edges ${Boost_LIBRARIES} ${CGAL_LIBRARIES}) 21 | 22 | add_executable(remesh_preserving_borders remesh_preserving_borders.cpp) 23 | target_link_libraries(remesh_preserving_borders ${Boost_LIBRARIES} ${CGAL_LIBRARIES}) 24 | 25 | add_executable(hierarchy_simplification hierarchy_simplification.cpp) 26 | target_link_libraries(hierarchy_simplification ${Boost_LIBRARIES} ${CGAL_LIBRARIES}) 27 | 28 | add_executable(wlop_simplification wlop_simplification.cpp) 29 | target_link_libraries(wlop_simplification ${Boost_LIBRARIES} ${CGAL_LIBRARIES}) 30 | 31 | add_executable(test_check_borders test_check_borders.cpp 32 | ../base/quantized_mesh_tile.cpp 33 | ../base/gzip_file_reader.cpp 34 | ../base/gzip_file_writer.cpp 35 | ../base/quantized_mesh.cpp) 36 | target_link_libraries(test_check_borders ${Boost_LIBRARIES} ${ZLIB_LIBRARIES} ${CTB_LIBRARY} ${GDAL_LIBRARY}) 37 | 38 | add_executable(detect_features_without_borders detect_features_without_borders.cpp) 39 | target_link_libraries(detect_features_without_borders ${Boost_LIBRARIES} ${CGAL_LIBRARIES}) 40 | 41 | add_executable(compute_statistics compute_statistics.cpp 42 | ../base/quantized_mesh_tile.cpp 43 | ../base/quantized_mesh_tiler.cpp 44 | ../base/gzip_file_reader.cpp 45 | ../base/gzip_file_writer.cpp 46 | ../base/quantized_mesh.cpp 47 | ../../3rdParty/meshoptimizer/vcacheoptimizer.cpp 48 | ../../3rdParty/meshoptimizer/vfetchoptimizer.cpp 49 | ../base/crs_conversions.cpp) 50 | target_link_libraries(compute_statistics ${Boost_LIBRARIES} ${ZLIB_LIBRARIES} ${CTB_LIBRARY} ${GDAL_LIBRARY}) -------------------------------------------------------------------------------- /src/dev-tests/Readme.md: -------------------------------------------------------------------------------- 1 | # Dev-tests 2 | 3 | The applications in this folder are just tools created during development for testing some of the functionalities in the main apps. 4 | 5 | Still, some of them may be useful for other applications not specifically related to this project. -------------------------------------------------------------------------------- /src/dev-tests/hierarchy_simplification.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Coronis Computing S.L. (Spain) 2 | // All rights reserved. 3 | // 4 | // This file is part of EMODnet Quantized Mesh Generator for Cesium. 5 | // 6 | // This program is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | // Author: Ricard Campos (ricardcd@gmail.com) 20 | 21 | /** 22 | * @file 23 | * @brief Simplifies a mesh using CGAL maintaining the edges on the border 24 | * @author Ricard Campos (ricardcd@gmail.com) 25 | */ 26 | 27 | #include 28 | #include 29 | #include "tin_creation/tin_creation_cgal_types.h" 30 | #include "cgal/polyhedron_builder_from_projected_triangulation.h" 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | // Boost 37 | #include 38 | 39 | using namespace std ; 40 | using namespace TinCreation ; 41 | namespace po = boost::program_options ; 42 | 43 | 44 | 45 | int main(int argc, char*argv[]) 46 | { 47 | int maxClusterSize ; 48 | double maxSurfaceVariance ; 49 | std::string inputFile, outputFile; 50 | po::options_description options("Simplifies a mesh using CGAL maintaining the edges on the border") ; 51 | options.add_options() 52 | ("help,h", "Produce help message") 53 | ("input,i", po::value(&inputFile), "Data points to create the mesh (they are supposed to be projectible to the XY plane, i.e., be an implicit function of the form f(x,y) = z).") 54 | ("output,o", po::value(&outputFile)->default_value("out.off"), "The output OFF file with the simplified mesh.") 55 | ("max-cluster-size", po::value(&maxClusterSize)->default_value(100), "Maximum cluster size.") 56 | ("max-surface-variance", po::value(&maxSurfaceVariance)->default_value(0.01), "Max surface variation.") 57 | ; 58 | 59 | po::positional_options_description positionalOptions; 60 | positionalOptions.add("input", 1); 61 | 62 | po::variables_map vm; 63 | po::store(po::command_line_parser(argc, argv).options(options).positional(positionalOptions).run(), vm); 64 | po::notify(vm); 65 | 66 | if (vm.count("help")) { 67 | cout << options << "\n"; 68 | return 1; 69 | } 70 | 71 | std::vector points; 72 | std::ifstream stream(inputFile); 73 | if (!stream || 74 | !CGAL::read_xyz_points(stream, std::back_inserter(points))) 75 | { 76 | std::cerr << "Error: cannot read file " << inputFile << std::endl; 77 | return EXIT_FAILURE; 78 | } 79 | std::cout << "Read " << points.size () << " point(s)" << std::endl; 80 | CGAL::Timer task_timer; task_timer.start(); 81 | 82 | // simplification by clustering using erase-remove idiom 83 | points.erase (CGAL::hierarchy_simplify_point_set (points.begin (), points.end (), 84 | maxClusterSize, // Max cluster size 85 | maxSurfaceVariance), // Max surface variation 86 | points.end ()); 87 | std::size_t memory = CGAL::Memory_sizer().virtual_size(); 88 | 89 | std::cout << points.size () << " point(s) kept, computed in " 90 | << task_timer.time() << " seconds, " 91 | << (memory>>20) << " Mib allocated." << std::endl; 92 | 93 | std::cout << "Triangulating the input points" << std::endl ; 94 | 95 | // Delaunay triangulation 96 | Delaunay dt( points.begin(), points.end() ); 97 | 98 | // Translate to Polyhedron 99 | Polyhedron surface ; 100 | PolyhedronBuilderFromProjectedTriangulation builder(dt); 101 | surface.delegate(builder); 102 | 103 | // Save the results 104 | std::ofstream of(outputFile); 105 | of << surface; 106 | 107 | return EXIT_SUCCESS; 108 | } 109 | -------------------------------------------------------------------------------- /src/dev-tests/qm_parser.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Coronis Computing S.L. (Spain) 2 | // All rights reserved. 3 | // 4 | // This file is part of EMODnet Quantized Mesh Generator for Cesium. 5 | // 6 | // This program is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | // Author: Ricard Campos (ricardcd@gmail.com) 20 | 21 | /** 22 | * @file 23 | * @brief Parses a quantized mesh terrain file and outputs some information in plain text on screen. 24 | * @author Ricard Campos (rcampos@eia.udg.edu) 25 | */ 26 | 27 | // Boost 28 | #include 29 | // Std 30 | #include 31 | // Project-specific 32 | #include "quantized_mesh_tile.h" 33 | // Cesium-terrain-builder 34 | #include 35 | 36 | using namespace std ; 37 | namespace po = boost::program_options ; 38 | 39 | 40 | 41 | int main ( int argc, char **argv) 42 | { 43 | // Parse input parameters 44 | std::string inputFile, outputFile ; 45 | int x = -1, y = -1, z = -1 ; 46 | bool headerOnly ; 47 | po::options_description options("Reads a quantized mesh terrain file") ; 48 | options.add_options() 49 | ( "help,h", "Produce help message" ) 50 | ( "input,i", po::value(&inputFile), "Input terrain file to parse" ) 51 | ( "output,o", po::value(&outputFile), "Output OFF file (Optional). The tile can be converted to this format to ease visualization in common 3D viewers" ) 52 | ( "tileX,x", po::value(&x), "Tile X" ) 53 | ( "tileY,y", po::value(&y), "Tile Y" ) 54 | ( "tileZ,z", po::value(&z), "Tile Zoom" ) 55 | ( "header", po::value(&headerOnly)->default_value(false), "Flag to show only the header of the tile on screen") 56 | ; 57 | 58 | po::variables_map vm ; 59 | po::store( po::parse_command_line(argc, argv, options), vm ) ; 60 | po::notify(vm); 61 | 62 | if (vm.count("help")) { 63 | cout << options << "\n"; 64 | return 1; 65 | } 66 | 67 | // Read the quantized mesh tile 68 | const ctb::TileCoordinate coord(z, x, y); 69 | QuantizedMeshTile qmt(coord); 70 | if ( !qmt.readFile(inputFile) ) { 71 | cerr << "[ERROR] Cannot read the input file" << endl ; 72 | return -1 ; 73 | } 74 | 75 | // Print information on screen 76 | if (headerOnly) 77 | qmt.printHeader() ; 78 | else 79 | qmt.print() ; 80 | 81 | // Export to OFF 82 | if (!outputFile.empty()) 83 | qmt.exportToOFF( outputFile, false ) ; 84 | 85 | return 1 ; 86 | } -------------------------------------------------------------------------------- /src/dev-tests/test_read_write.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Coronis Computing S.L. (Spain) 2 | // All rights reserved. 3 | // 4 | // This file is part of EMODnet Quantized Mesh Generator for Cesium. 5 | // 6 | // This program is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | // Author: Ricard Campos (ricardcd@gmail.com) 20 | 21 | /** 22 | * @file 23 | * @brief Reads a quantized mesh terrain file, writes it to disk, and reads it back. 24 | * @author Ricard Campos (ricardcd@gmail.com) 25 | */ 26 | 27 | // Boost 28 | #include 29 | // Std 30 | #include 31 | // Project-specific 32 | #include "quantized_mesh_tile.h" 33 | // Cesium-terrain-builder 34 | #include 35 | 36 | using namespace std ; 37 | namespace po = boost::program_options ; 38 | 39 | 40 | 41 | int main ( int argc, char **argv) 42 | { 43 | // Parse input parameters 44 | std::string inputFile, outputFile ; 45 | int x = -1, y = -1, z = -1 ; 46 | po::options_description options("Reads a quantized mesh terrain file, writes it to disk, and reads it back.\n" 47 | "The contents are shown in plain text on the screen for visual comparison") ; 48 | options.add_options() 49 | ( "help,h", "Produce help message" ) 50 | ( "input,i", po::value(&inputFile), "Input terrain file to parse" ) 51 | ( "output,o", po::value(&outputFile)->default_value("./tmp.terrain"), "Output terrain file to write. The input file will be read and written back using library functions. Results should be the same!" ) 52 | ( "tileX,x", po::value(&x), "Tile X" ) 53 | ( "tileY,y", po::value(&y), "Tile Y" ) 54 | ( "tileZ,z", po::value(&z), "Tile Zoom" ) 55 | ; 56 | 57 | po::variables_map vm ; 58 | po::store( po::parse_command_line(argc, argv, options), vm ) ; 59 | po::notify(vm); 60 | 61 | if (vm.count("help")) { 62 | cout << options << "\n"; 63 | return 1; 64 | } 65 | 66 | // Read the quantized mesh tile 67 | cout << "- Reading the file " << inputFile << endl ; 68 | const ctb::TileCoordinate coord(z, x, y); 69 | QuantizedMeshTile qmt(coord); 70 | if ( !qmt.readFile(inputFile) ) { 71 | cerr << "[ERROR] Cannot read the input file" << endl ; 72 | return -1 ; 73 | } 74 | 75 | // Print information on screen 76 | qmt.print() ; 77 | 78 | // Write it to file 79 | cout << "- Writing the file " << outputFile << endl ; 80 | if ( !qmt.writeFile( outputFile ) ) { 81 | cerr << "[ERROR] Cannot write the output file" << endl ; 82 | return -1 ; 83 | } 84 | 85 | // Read the written file back and check if it is the same as input 86 | cout << "- Reading the file " << outputFile << " back" << endl ; 87 | QuantizedMeshTile qmt2(coord); 88 | if ( !qmt2.readFile( outputFile ) ) { 89 | cerr << "[ERROR] Cannot read the output file" << endl ; 90 | return -1 ; 91 | } 92 | 93 | qmt2.print() ; 94 | 95 | return 1 ; 96 | } -------------------------------------------------------------------------------- /src/dev-tests/wlop_simplification.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Coronis Computing S.L. (Spain) 2 | // All rights reserved. 3 | // 4 | // This file is part of EMODnet Quantized Mesh Generator for Cesium. 5 | // 6 | // This program is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | // Author: Ricard Campos (ricardcd@gmail.com) 20 | 21 | /** 22 | * @file 23 | * @brief Simplifies the input point set using the WLOP algorithm, and triangulates it in the 2D plane. 24 | * @author Ricard Campos (ricardcd@gmail.com) 25 | */ 26 | 27 | #include 28 | #include 29 | #include "tin_creation/tin_creation_cgal_types.h" 30 | #include "cgal/cgal_utils.h" 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include "cgal/polyhedron_builder_from_projected_triangulation.h" 37 | // Boost 38 | #include 39 | 40 | using namespace std ; 41 | using namespace TinCreation ; 42 | namespace po = boost::program_options ; 43 | 44 | // Concurrency 45 | #ifdef CGAL_LINKED_WITH_TBB 46 | typedef CGAL::Parallel_tag Concurrency_tag; 47 | #else 48 | typedef CGAL::Sequential_tag Concurrency_tag; 49 | #endif 50 | 51 | int main(int argc, char*argv[]) 52 | { 53 | double percentToRetain, neighborRadius ; 54 | std::string inputFile, outputFile; 55 | po::options_description options("Simplifies the input point set using the WLOP algorithm, and triangulates it in the 2D plane") ; 56 | options.add_options() 57 | ("help,h", "Produce help message") 58 | ("input,i", po::value(&inputFile), "Data points to create the mesh (they are supposed to be projectible to the XY plane, i.e., be an implicit function of the form f(x,y) = z).") 59 | ("output,o", po::value(&outputFile)->default_value("out.off"), "The output OFF file with the simplified mesh.") 60 | ("percent-to-retain", po::value(&percentToRetain)->default_value(10), "Percentage of points to retain") 61 | ("neighbor-radius", po::value(&neighborRadius)->default_value(0.5), "Neighbors size (automatic guess if smaller than zero)") 62 | ; 63 | 64 | po::positional_options_description positionalOptions; 65 | positionalOptions.add("input", 1); 66 | 67 | po::variables_map vm; 68 | po::store(po::command_line_parser(argc, argv).options(options).positional(positionalOptions).run(), vm); 69 | po::notify(vm); 70 | 71 | if (vm.count("help")) { 72 | cout << options << "\n"; 73 | return 1; 74 | } 75 | 76 | std::vector points; 77 | std::ifstream stream(inputFile); 78 | if (!stream || 79 | !CGAL::read_xyz_points(stream, std::back_inserter(points))) 80 | { 81 | std::cerr << "Error: cannot read file " << inputFile << std::endl; 82 | return EXIT_FAILURE; 83 | } 84 | std::cout << "Read " << points.size () << " point(s)" << std::endl; 85 | CGAL::Timer task_timer; task_timer.start(); 86 | 87 | // Simplification of the point set using WLOP 88 | std::vector simpPts ; 89 | CGAL::wlop_simplify_and_regularize_point_set 90 | 91 | (points.begin(), 92 | points.end(), 93 | std::back_inserter(simpPts), 94 | percentToRetain, 95 | neighborRadius 96 | ); 97 | std::size_t memory = CGAL::Memory_sizer().virtual_size(); 98 | 99 | std::cout << simpPts.size () << " point(s) kept, computed in " 100 | << task_timer.time() << " seconds, " 101 | << (memory>>20) << " Mib allocated." << std::endl; 102 | 103 | std::cout << "Triangulating the input points" << std::endl ; 104 | 105 | // Delaunay triangulation 106 | Delaunay dt( simpPts.begin(), simpPts.end() ); 107 | 108 | std::cout << "Resulting triangulation has:" << std::endl ; 109 | std::cout << " - " << dt.number_of_vertices() << " vertices" << std::endl ; 110 | std::cout << " - " << dt.number_of_faces() << " triangles" << std::endl ; 111 | 112 | // Translate to Polyhedron 113 | Polyhedron surface ; 114 | PolyhedronBuilderFromProjectedTriangulation builder(dt); 115 | surface.delegate(builder); 116 | 117 | // Save the results 118 | std::ofstream of(outputFile); 119 | of << surface; 120 | 121 | return EXIT_SUCCESS; 122 | } 123 | -------------------------------------------------------------------------------- /src/tin_creation/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(TinCreation SHARED tin_creator.cpp 2 | tin_creation_delaunay_strategy.cpp 3 | tin_creation_greedy_insertion_strategy.cpp 4 | tin_creation_remeshing_strategy.cpp 5 | tin_creation_simplification_lindstrom_turk_strategy.cpp 6 | tin_creation_simplification_point_set.cpp 7 | tin_creation_simplification_point_set_grid.cpp 8 | tin_creation_simplification_point_set_hierarchy.cpp 9 | tin_creation_simplification_point_set_random.cpp 10 | tin_creation_simplification_point_set_wlop.cpp 11 | ../base/crs_conversions.cpp) 12 | 13 | set_target_properties(TinCreation PROPERTIES PUBLIC_HEADER tin_creator.h 14 | tin_creation_cgal_types.h 15 | tin_creation_delaunay_strategy.h 16 | tin_creation_greedy_insertion_strategy.h 17 | tin_creation_remeshing_strategy.h 18 | tin_creation_simplification_lindstrom_turk_strategy.h 19 | tin_creation_simplification_point_set.h 20 | tin_creation_simplification_point_set_grid.h 21 | tin_creation_simplification_point_set_hierarchy.h 22 | tin_creation_simplification_point_set_random.h 23 | tin_creation_simplification_point_set_wlop.h) 24 | 25 | install(TARGETS TinCreation 26 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 27 | PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) -------------------------------------------------------------------------------- /src/tin_creation/tin_creation_cgal_types.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Coronis Computing S.L. (Spain) 2 | // All rights reserved. 3 | // 4 | // This file is part of EMODnet Quantized Mesh Generator for Cesium. 5 | // 6 | // This program is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | // Author: Ricard Campos (ricardcd@gmail.com) 20 | 21 | #ifndef EMODNET_QMGC_CGAL_DEFINES_H 22 | #define EMODNET_QMGC_CGAL_DEFINES_H 23 | 24 | /*! @namespace TinCreation 25 | @brief This namespace contains all the types/classes/functions required to create a TIN out of a regularly gridded terrain 26 | */ 27 | 28 | /** 29 | * @brief Common types of CGAL used in the project. 30 | * 31 | * We decided to fix the types because we don't envision changing the Kernel used, and also because doing so we avoid the 32 | * use of templated classes. 33 | */ 34 | 35 | // CGAL includes 36 | #include 37 | // Remeshing (add these before, otherwise we get problems with some defines...) 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | 50 | // Simplification 51 | #include 52 | #include // Stop-condition policy based on a fixed number of desired output edges 53 | #include // // Stop-condition policy that stops when the number of undirected edges drops below a given % of the initial count 54 | #include 55 | #include 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | #include 63 | 64 | // STD 65 | #include 66 | 67 | namespace TinCreation { 68 | 69 | // Renaming of namespaces 70 | namespace SMS = CGAL::Surface_mesh_simplification; 71 | namespace PS = CGAL::Polyline_simplification_2; 72 | 73 | // CGAL types 74 | typedef CGAL::Exact_predicates_inexact_constructions_kernel K; 75 | //typedef CGAL::Simple_cartesian K; 76 | typedef K::FT FT; 77 | typedef CGAL::Projection_traits_xy_3 Gt; 78 | typedef CGAL::Delaunay_triangulation_2 Delaunay; 79 | typedef K::Point_3 Point_3; 80 | typedef K::Point_2 Point_2; 81 | typedef K::Vector_2 Vector_2; 82 | typedef K::Vector_3 Vector_3; 83 | typedef K::Segment_2 Segment_2; 84 | typedef std::vector Polyline; 85 | typedef std::vector PointCloud; 86 | typedef std::vector Polylines; 87 | 88 | // Remeshing related 89 | typedef CGAL::Polyhedral_mesh_domain_with_features_3 MeshDomain; 90 | typedef CGAL::Mesh_triangulation_3::type Tr; // Triangulation 91 | typedef CGAL::Mesh_complex_3_in_triangulation_3< 92 | Tr, 93 | MeshDomain::Corner_index, 94 | MeshDomain::Curve_segment_index> C3T3; 95 | typedef CGAL::Mesh_criteria_3 MeshCriteria; // Criteria 96 | 97 | typedef CGAL::Mesh_polyhedron_3::type Polyhedron; 98 | typedef Polyhedron::HalfedgeDS HalfedgeDS; 99 | typedef Polyhedron::Halfedge_handle Halfedge_handle; 100 | typedef Polyhedron::Vertex_handle Vertex_handle; 101 | typedef boost::graph_traits::vertex_descriptor VertexDescriptor; 102 | typedef boost::graph_traits::face_descriptor FaceDescriptor; 103 | typedef std::map VertexNormalMap; 104 | typedef boost::associative_property_map VertexNormalPropertyMap; 105 | 106 | // Simplification related 107 | typedef CGAL::Min_sphere_of_points_d_traits_3 MinSphereTraits; 108 | typedef CGAL::Min_sphere_of_spheres_d MinSphere; 109 | typedef MinSphereTraits::Sphere Sphere; 110 | typedef SMS::LindstromTurk_cost SimplificationCost; 111 | typedef SMS::LindstromTurk_params SimplificationCostParams; 112 | typedef SMS::Bounded_normal_change_placement< 113 | SMS::LindstromTurk_placement > SimplificationPlacement; // Note: Do not change this to use edge_length cost! While it lowers computational overhead, it will certainly destroy the border edges 114 | typedef SMS::Count_stop_predicate SimplificationStopPredicate; 115 | 116 | // Polyline simplification related 117 | typedef PS::Stop_above_cost_threshold PSStopCost; 118 | 119 | #ifdef CGAL_LINKED_WITH_TBB 120 | typedef CGAL::Parallel_tag Concurrency_tag; 121 | #else 122 | typedef CGAL::Sequential_tag Concurrency_tag; 123 | #endif 124 | 125 | } // End namespace TinCreation 126 | 127 | #endif //EMODNET_QMGC_CGAL_DEFINES_H 128 | -------------------------------------------------------------------------------- /src/tin_creation/tin_creation_delaunay_strategy.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Coronis Computing S.L. (Spain) 2 | // All rights reserved. 3 | // 4 | // This file is part of EMODnet Quantized Mesh Generator for Cesium. 5 | // 6 | // This program is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | // Author: Ricard Campos (ricardcd@gmail.com) 20 | 21 | #include "tin_creation_delaunay_strategy.h" 22 | #include "tin_creation_cgal_types.h" 23 | #include "cgal/polyhedron_builder_from_projected_triangulation.h" 24 | 25 | namespace TinCreation { 26 | 27 | Polyhedron TinCreationDelaunayStrategy::create(const std::vector &dataPts, 28 | const bool &constrainEasternVertices, 29 | const bool &constrainWesternVertices, 30 | const bool &constrainNorthernVertices, 31 | const bool &constrainSouthernVertices) { 32 | // Delaunay triangulation 33 | Delaunay dt(dataPts.begin(), dataPts.end()); 34 | 35 | // Translate to Polyhedron 36 | Polyhedron surface; 37 | PolyhedronBuilderFromProjectedTriangulation builder(dt); 38 | surface.delegate(builder); 39 | 40 | return surface; 41 | } 42 | 43 | } // End namespace TinCreation -------------------------------------------------------------------------------- /src/tin_creation/tin_creation_delaunay_strategy.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Coronis Computing S.L. (Spain) 2 | // All rights reserved. 3 | // 4 | // This file is part of EMODnet Quantized Mesh Generator for Cesium. 5 | // 6 | // This program is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | // Author: Ricard Campos (ricardcd@gmail.com) 20 | 21 | #ifndef EMODNET_QMGC_TIN_CREATION_DELAUNAY_H 22 | #define EMODNET_QMGC_TIN_CREATION_DELAUNAY_H 23 | 24 | #include "tin_creation/tin_creator.h" 25 | 26 | namespace TinCreation { 27 | 28 | /** 29 | * @class TinCreationDelaunayStrategy 30 | * @brief A Delaunay triangulation is created with the input points, no simplification is applied. 31 | * 32 | * Also, the constrainVertices parameters are ignored. This creation strategy is useful to just triangulate regular 33 | * grids, where the vertices at the borders are always the same for neighboring tiles. 34 | */ 35 | class TinCreationDelaunayStrategy : public TinCreationStrategy { 36 | public: 37 | TinCreationDelaunayStrategy() {}; 38 | 39 | Polyhedron create(const std::vector &dataPts, 40 | const bool &constrainEasternVertices, 41 | const bool &constrainWesternVertices, 42 | const bool &constrainNorthernVertices, 43 | const bool &constrainSouthernVertices); 44 | 45 | void setParamsForZoom(const unsigned int& zoom) {} 46 | }; 47 | 48 | } // End namespace TinCreation 49 | 50 | #endif //EMODNET_QMGC_TIN_CREATION_DELAUNAY_H 51 | -------------------------------------------------------------------------------- /src/tin_creation/tin_creation_remeshing_strategy.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Coronis Computing S.L. (Spain) 2 | // All rights reserved. 3 | // 4 | // This file is part of EMODnet Quantized Mesh Generator for Cesium. 5 | // 6 | // This program is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | // Author: Ricard Campos (ricardcd@gmail.com) 20 | 21 | #ifndef EMODNET_QMGC_TIN_CREATION_REMESHING_H 22 | #define EMODNET_QMGC_TIN_CREATION_REMESHING_H 23 | 24 | #include "tin_creator.h" 25 | #include "tin_creation_utils.h" 26 | 27 | namespace TinCreation { 28 | 29 | /** 30 | * @class TinCreationRemeshingStrategy 31 | * @brief Creates a TIN using Delaunay refinement algorithm 32 | * 33 | * In fact, the method used in this class is not a simplification but a remeshing process. 34 | * 35 | * Starting from a high resolution mesh, we obtain a new mesh following a set of requirements on the final mesh: 36 | * 37 | * - facet_distance: Upper bound for the distance between the facet circumcenter and the center of its surface Delaunay ball (i.e., approximation accuracy) 38 | * - facet_angle: Lower bound for the angles (in degrees) of the surface mesh facets 39 | * - facet_size: Upper bound for the radii of the surface Delaunay balls 40 | * - edge_size: Upper bound for the lengths of the boundary edges 41 | * 42 | * When the simplification takes place, all the coordinates of the vertices are normalized between 0..1 43 | * Note that this also means that, if the parameters are not set wisely, using this process we can 44 | * get a mesh of even larger complexity with respect to the original one! 45 | */ 46 | class TinCreationRemeshingStrategy : public TinCreationStrategy 47 | { 48 | public: 49 | TinCreationRemeshingStrategy( double facetDistance, 50 | double facetAngle, 51 | double facetSize, 52 | double edgeSize) 53 | : m_facetAngle(facetAngle) 54 | { 55 | m_facetDistancePerZoom = std::vector{facetDistance}; 56 | m_facetSizePerZoom = std::vector{facetSize}; 57 | m_edgeSizePerZoom = std::vector{edgeSize}; 58 | setParamsForZoom(0); 59 | } 60 | 61 | TinCreationRemeshingStrategy(const std::vector& facetDistance, 62 | double facetAngle, 63 | const std::vector& facetSize, 64 | const std::vector& edgeSize) 65 | : m_facetDistancePerZoom(facetDistance) 66 | , m_facetAngle(facetAngle) 67 | , m_facetSizePerZoom(facetSize) 68 | , m_edgeSizePerZoom(edgeSize) 69 | { 70 | setParamsForZoom(0); 71 | } 72 | 73 | Polyhedron create(const std::vector& dataPts, 74 | const bool& constrainEasternVertices, 75 | const bool& constrainWesternVertices, 76 | const bool& constrainNorthernVertices, 77 | const bool& constrainSouthernVertices); 78 | 79 | // WARNING: The remeshing strategy should not be used for tiled rendering! 80 | void setParamsForZoom(const unsigned int& zoom) { 81 | m_facetDistance = standardHandlingOfThresholdPerZoom(m_facetDistancePerZoom, zoom); 82 | m_facetSize = standardHandlingOfThresholdPerZoom(m_facetSizePerZoom, zoom); 83 | m_edgeSize = standardHandlingOfThresholdPerZoom(m_edgeSizePerZoom, zoom); 84 | } 85 | 86 | private: 87 | // Algorithm parameters 88 | double m_facetDistance; 89 | double m_facetAngle; 90 | double m_facetSize; 91 | double m_edgeSize; 92 | std::vector m_facetDistancePerZoom; 93 | std::vector m_facetSizePerZoom; 94 | std::vector m_edgeSizePerZoom; 95 | 96 | // Internal functions 97 | 98 | /// Checks if all input points are collinear 99 | bool dataPtsArePlanar(const std::vector& dataPts) const; 100 | 101 | /// Sets the default points for a planar tile, using a set of planar points for refinement will not work (don't know why!) 102 | std::vector defaultPointsForPlanarTile() const; 103 | 104 | /// Splits a polyline into individual edges 105 | /// Pre-condition: poly contains a sorted set of points (either vertically or horizontally, depending on the border they come from) 106 | Polylines borderPolylineToIndividualEdges(Polyline& poly); 107 | }; 108 | 109 | } // End namespace TinCreation 110 | 111 | #endif //EMODNET_QMGC_TIN_CREATION_REMESHING_H 112 | -------------------------------------------------------------------------------- /src/tin_creation/tin_creation_simplification_lindstrom_turk_strategy.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Coronis Computing S.L. (Spain) 2 | // All rights reserved. 3 | // 4 | // This file is part of EMODnet Quantized Mesh Generator for Cesium. 5 | // 6 | // This program is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | // Author: Ricard Campos (ricardcd@gmail.com) 20 | 21 | #include "tin_creation_simplification_lindstrom_turk_strategy.h" 22 | #include "tin_creation_cgal_types.h" 23 | #include "cgal/border_edges_are_constrained_edge_map.h" 24 | #include "cgal/corner_vertices_are_constrained_vertex_map.h" 25 | #include "cgal/further_constrained_placement.h" 26 | #include "cgal/polyhedron_builder_from_projected_triangulation.h" 27 | 28 | namespace TinCreation { 29 | 30 | Polyhedron TinCreationSimplificationLindstromTurkStrategy::create( const std::vector& dataPts, 31 | const bool& constrainEasternVertices, 32 | const bool& constrainWesternVertices, 33 | const bool& constrainNorthernVertices, 34 | const bool& constrainSouthernVertices ) 35 | { 36 | // Delaunay triangulation 37 | Delaunay dt( dataPts.begin(), dataPts.end() ); 38 | 39 | // Translate to Polyhedron 40 | Polyhedron surface ; 41 | PolyhedronBuilderFromProjectedTriangulation builder(dt); 42 | surface.delegate(builder); 43 | 44 | // Set up the edge constrainer 45 | typedef SMS::FurtherConstrainedPlacement, 47 | CornerVerticesAreConstrainedVertexMap > SimplificationConstrainedPlacement ; 48 | BorderEdgesAreConstrainedEdgeMap beac( surface, 49 | constrainEasternVertices, 50 | constrainWesternVertices, 51 | constrainNorthernVertices, 52 | constrainSouthernVertices ) ; 53 | CornerVerticesAreConstrainedVertexMap cvacvm(surface) ; 54 | SimplificationConstrainedPlacement scp( beac, cvacvm ) ; 55 | SimplificationCost sc( SimplificationCostParams( m_weightVolume, 56 | m_weightBoundary, 57 | m_weightShape ) ) ; 58 | 59 | // TODO: Find a way to provide an intuitive stop predicate based on cost... 60 | int r = SMS::edge_collapse 61 | ( surface, 62 | SimplificationStopPredicate(m_stopEdgesCount), 63 | // cacsp, 64 | CGAL::parameters::vertex_index_map( get( CGAL::vertex_external_index,surface ) ) 65 | .halfedge_index_map(get(CGAL::halfedge_external_index, surface)) 66 | .get_cost(sc) 67 | // .get_placement(pl) 68 | // .get_placement(SimplificationPlacement()) 69 | .get_placement(scp) 70 | .edge_is_constrained_map(beac) 71 | ) ; 72 | 73 | return surface ; 74 | } 75 | 76 | 77 | } // End namespace TinCreation -------------------------------------------------------------------------------- /src/tin_creation/tin_creation_simplification_lindstrom_turk_strategy.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Coronis Computing S.L. (Spain) 2 | // All rights reserved. 3 | // 4 | // This file is part of EMODnet Quantized Mesh Generator for Cesium. 5 | // 6 | // This program is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | // Author: Ricard Campos (ricardcd@gmail.com) 20 | 21 | #ifndef EMODNET_QMGC_TIN_CREATION_LINDSTROM_TURK_STRATEGY_H 22 | #define EMODNET_QMGC_TIN_CREATION_LINDSTROM_TURK_STRATEGY_H 23 | 24 | #include "tin_creator.h" 25 | 26 | namespace TinCreation { 27 | 28 | /** 29 | * @class TinCreationSimplificationLindstromTurkStrategy 30 | * 31 | * @brief Creates a TIN using an edge-collapse simplification method 32 | * 33 | * This class uses a modified version of the Lindstrom-Turk algorithm [1][2] 34 | * 35 | * [1] P. Lindstrom and G. Turk. Fast and memory efficient polygonal simplification. In IEEE Visualization, pages 279–286, 1998.
36 | * [2] P. Lindstrom and G. Turk. Evaluation of memoryless simplification. IEEE Transactions on Visualization and Computer Graphics, 5(2):98–115, slash 1999. 37 | */ 38 | class TinCreationSimplificationLindstromTurkStrategy : public TinCreationStrategy { 39 | public: 40 | /** 41 | * Constructor 42 | * @param stopEdgesCount Desired number of edges for the simplified mesh 43 | * @param weightVolume Volume weight (see original reference) 44 | * @param weightBoundary Boundary weight (see original reference) 45 | * @param weightShape Shape weight (see original reference) 46 | */ 47 | TinCreationSimplificationLindstromTurkStrategy(int stopEdgesCount, 48 | double weightVolume = 0.5, 49 | double weightBoundary = 0.5, 50 | double weightShape = 1e-10) 51 | : m_stopEdgesCount(stopEdgesCount) 52 | , m_weightVolume(weightVolume) 53 | , m_weightBoundary(weightBoundary) 54 | , m_stopEdgesCountPerZoom(1, stopEdgesCount) 55 | , m_weightShape(weightShape) {} 56 | 57 | /** 58 | * Constructor 59 | * @param stopEdgesCount Desired number of edges for the simplified mesh per zoom 60 | * @param weightVolume Volume weight (see original reference) 61 | * @param weightBoundary Boundary weight (see original reference) 62 | * @param weightShape Shape weight (see original reference) 63 | */ 64 | TinCreationSimplificationLindstromTurkStrategy(std::vector stopEdgesCountPerZoom, 65 | double weightVolume = 0.5, 66 | double weightBoundary = 0.5, 67 | double weightShape = 1e-10) 68 | : m_stopEdgesCountPerZoom(stopEdgesCountPerZoom), m_weightVolume(weightVolume), m_weightBoundary(weightBoundary), 69 | m_weightShape(weightShape) 70 | { 71 | setParamsForZoom(0); 72 | } 73 | 74 | void setParamsForZoom(const unsigned int& zoom) { 75 | if (m_stopEdgesCountPerZoom.size() == 0) { 76 | std::cerr << "[WARNING::TinCreationSimplificationLindstromTurkStrategy] Input edges count per zoom vector is empty, using 500 (default value)" << std::endl; 77 | m_stopEdgesCount = 500; 78 | } 79 | else if (zoom < m_stopEdgesCountPerZoom.size()) 80 | // Use the edges count corresponding to the required zoom 81 | m_stopEdgesCount = m_stopEdgesCountPerZoom[zoom]; 82 | else { 83 | // Use the edges count corresponding to the last zoom specified in the vector 84 | m_stopEdgesCount = m_stopEdgesCountPerZoom.back(); 85 | } 86 | } 87 | 88 | Polyhedron create(const std::vector &dataPts, 89 | const bool &constrainEasternVertices, 90 | const bool &constrainWesternVertices, 91 | const bool &constrainNorthernVertices, 92 | const bool &constrainSouthernVertices); 93 | 94 | private: 95 | // Algorithm parameters 96 | int m_stopEdgesCount; // Simplification edges count stop condition. If the number of edges in the surface being simplified drops below this threshold the process finishes 97 | double m_weightVolume; // Weight for the volume part of Lindstrom-Turk's cost function 98 | double m_weightBoundary; // Weight for the boundary part of Lindstrom-Turk's cost function 99 | double m_weightShape; // Weight for the shape part of Lindstrom-Turk's cost function 100 | std::vector m_stopEdgesCountPerZoom; // Vector of desired edges count per zoom level 101 | }; 102 | 103 | } // End namespace TinCreation 104 | 105 | #endif //EMODNET_QMGC_TIN_CREATION_LINDSTROM_TURK_STRATEGY_H 106 | -------------------------------------------------------------------------------- /src/tin_creation/tin_creation_simplification_point_set_grid.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Coronis Computing S.L. (Spain) 2 | // All rights reserved. 3 | // 4 | // This file is part of EMODnet Quantized Mesh Generator for Cesium. 5 | // 6 | // This program is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | // Author: Ricard Campos (ricardcd@gmail.com) 20 | 21 | #include "tin_creation_simplification_point_set_grid.h" 22 | #include 23 | 24 | namespace TinCreation { 25 | 26 | std::vector 27 | TinCreationSimplificationPointSetGrid:: 28 | simplify(const std::vector &pts) { 29 | // Convert to metric 30 | std::vector ptsToSimpECEF = this->convertUVHToECEF(pts); 31 | 32 | // Simplify using grid simplification (erase-remove idiom) 33 | ptsToSimpECEF.erase(CGAL::grid_simplify_point_set(ptsToSimpECEF.begin(), 34 | ptsToSimpECEF.end(), 35 | m_cellSize), 36 | ptsToSimpECEF.end()); 37 | 38 | // Convert to the local (XY-projectable) coordinates again 39 | std::vector ptsSimp = this->convertECEFToUVH(ptsToSimpECEF); 40 | 41 | return ptsSimp; 42 | } 43 | 44 | } // End namespace TinCreation -------------------------------------------------------------------------------- /src/tin_creation/tin_creation_simplification_point_set_grid.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Coronis Computing S.L. (Spain) 2 | // All rights reserved. 3 | // 4 | // This file is part of EMODnet Quantized Mesh Generator for Cesium. 5 | // 6 | // This program is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | // Author: Ricard Campos (ricardcd@gmail.com) 20 | 21 | #ifndef EMODNET_QMGC_TIN_CREATION_SIMPLIFICATION_POINT_SET_GRID_H 22 | #define EMODNET_QMGC_TIN_CREATION_SIMPLIFICATION_POINT_SET_GRID_H 23 | 24 | #include "tin_creation_simplification_point_set.h" 25 | #include "tin_creation_utils.h" 26 | 27 | namespace TinCreation { 28 | 29 | /** 30 | * @class TinCreationSimplificationPointSetGrid 31 | * @brief Creates a TIN using the Grid point set simplification algorithm 32 | * 33 | * A regular grid of points is overlayed on the data, and a representative point is selected from within each cell. 34 | */ 35 | class TinCreationSimplificationPointSetGrid 36 | : public TinCreationSimplificationPointSet 37 | { 38 | public: 39 | /** 40 | * Constructor 41 | * @param borderSimplificationMaxDistance Maximum error for polyline simplification 42 | * @param borderSimplificationMaxLengthPercent Maximum length for an edge in the simplified polyline. This prevents oversimplification in planar tiles. 43 | * @param minFeaturePolylineSize Minimum number of connected edges in a sharp feature polyline to consider it during processing 44 | * @param cellSize Cell size 45 | */ 46 | TinCreationSimplificationPointSetGrid(double borderSimplificationMaxDistance, 47 | double borderSimplificationMaxLength, 48 | unsigned int minFeaturePolylineSize, 49 | double cellSize) 50 | : TinCreationSimplificationPointSet(borderSimplificationMaxDistance, 51 | borderSimplificationMaxLength, 52 | minFeaturePolylineSize) 53 | { 54 | m_cellSizePerZoom = std::vector{m_cellSize}; 55 | setParamsForZoomConcreteStrategy(0); 56 | } 57 | 58 | /** 59 | * Constructor 60 | * @param borderSimplificationMaxDistance Maximum error for polyline simplification per zoom 61 | * @param borderSimplificationMaxLengthPercent Maximum length for an edge in the simplified polyline per zoom. This prevents oversimplification in planar tiles. 62 | * @param minFeaturePolylineSize Minimum number of connected edges in a sharp feature polyline to consider it during processing 63 | * @param cellSize Cell size 64 | */ 65 | TinCreationSimplificationPointSetGrid(const std::vector& borderSimplificationMaxDistancePerZoom, 66 | const std::vector& borderSimplificationMaxLengthPerZoom, 67 | unsigned int minFeaturePolylineSize, 68 | const std::vector& cellSizePerZoom) 69 | : TinCreationSimplificationPointSet(borderSimplificationMaxDistancePerZoom, 70 | borderSimplificationMaxLengthPerZoom, 71 | minFeaturePolylineSize), 72 | m_cellSizePerZoom(cellSizePerZoom) 73 | { 74 | setParamsForZoomConcreteStrategy(0); 75 | } 76 | 77 | std::vector simplify(const std::vector& pts); 78 | 79 | void setParamsForZoomConcreteStrategy(const unsigned int& zoom) { 80 | m_cellSize = standardHandlingOfThresholdPerZoom(m_cellSizePerZoom, zoom); 81 | } 82 | 83 | private: 84 | // --- Attributes --- 85 | double m_cellSize ; 86 | std::vector m_cellSizePerZoom; 87 | }; 88 | 89 | } // End namespace TinCreation 90 | 91 | #endif //EMODNET_QMGC_TIN_CREATION_SIMPLIFICATION_POINT_SET_GRID_H 92 | -------------------------------------------------------------------------------- /src/tin_creation/tin_creation_simplification_point_set_hierarchy.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Coronis Computing S.L. (Spain) 2 | // All rights reserved. 3 | // 4 | // This file is part of EMODnet Quantized Mesh Generator for Cesium. 5 | // 6 | // This program is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | // Author: Ricard Campos (ricardcd@gmail.com) 20 | 21 | #include "tin_creation_simplification_point_set_hierarchy.h" 22 | #include 23 | #include 24 | 25 | namespace TinCreation { 26 | 27 | std::vector 28 | TinCreationSimplificationPointSetHierarchy:: 29 | simplify(const std::vector &pts) { 30 | // Convert to metric 31 | std::vector ptsToSimpECEF = this->convertUVHToECEF(pts); 32 | 33 | // Simplify using hierarchical point set simplification (erase-remove idiom) 34 | ptsToSimpECEF.erase(CGAL::hierarchy_simplify_point_set(ptsToSimpECEF.begin(), 35 | ptsToSimpECEF.end(), 36 | m_maxClusterSize, // Max cluster size 37 | m_maxSurfaceVariance), // Max surface variation 38 | ptsToSimpECEF.end()); 39 | 40 | // Convert to the local (XY-projectable) coordinates again 41 | std::vector ptsSimp = this->convertECEFToUVH(ptsToSimpECEF); 42 | 43 | return ptsSimp; 44 | } 45 | 46 | } // End namespace TinCreation -------------------------------------------------------------------------------- /src/tin_creation/tin_creation_simplification_point_set_hierarchy.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Coronis Computing S.L. (Spain) 2 | // All rights reserved. 3 | // 4 | // This file is part of EMODnet Quantized Mesh Generator for Cesium. 5 | // 6 | // This program is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | // Author: Ricard Campos (ricardcd@gmail.com) 20 | 21 | #ifndef EMODNET_QMGC_TIN_CREATION_SIMPLIFICATION_POINT_SET_HIERARCHY_H 22 | #define EMODNET_QMGC_TIN_CREATION_SIMPLIFICATION_POINT_SET_HIERARCHY_H 23 | 24 | #include "tin_creation_simplification_point_set.h" 25 | #include "tin_creation_utils.h" 26 | 27 | namespace TinCreation { 28 | 29 | /** 30 | * @class TinCreationSimplificationPointSetHierarchy 31 | * @brief Creates a TIN using the Hierarchical point set simplification algorithm 32 | * 33 | * It uses CGAL's implementation of the method described in:
34 | * Mark Pauly, Markus Gross, and Leif P Kobbelt. Efficient simplification of point-sampled surfaces. In Proceedings of the conference on Visualization'02, pages 163–170. IEEE Computer Society, 2002. 35 | */ 36 | class TinCreationSimplificationPointSetHierarchy 37 | : public TinCreationSimplificationPointSet 38 | { 39 | public: 40 | /** 41 | * Constructor 42 | * @param borderSimplificationMaxDistance Maximum error for polyline simplification 43 | * @param borderSimplificationMaxLengthPercent Maximum length for an edge in the simplified polyline. This prevents oversimplification in planar tiles. 44 | * @param minFeaturePolylineSize Minimum number of connected edges in a sharp feature polyline to consider it during processing 45 | * @param maxClusterSize Maximum cluster size 46 | * @param maxSurfaceVariance Maximum cluster variation value 47 | */ 48 | TinCreationSimplificationPointSetHierarchy(double borderSimplificationMaxDistance, 49 | double borderSimplificationMaxLength, 50 | unsigned int minFeaturePolylineSize, 51 | unsigned int maxClusterSize, 52 | double maxSurfaceVariance) 53 | : TinCreationSimplificationPointSet(borderSimplificationMaxDistance, 54 | borderSimplificationMaxLength, 55 | minFeaturePolylineSize) 56 | { 57 | m_maxClusterSizePerZoom = std::vector{maxClusterSize}; 58 | m_maxSurfaceVariancePerZoom = std::vector{maxSurfaceVariance}; 59 | setParamsForZoomConcreteStrategy(0); 60 | } 61 | 62 | /** 63 | * Constructor 64 | * @param borderSimplificationMaxDistance Maximum error for polyline simplification per zoom 65 | * @param borderSimplificationMaxLengthPercent Maximum length for an edge in the simplified polyline per zoom. This prevents oversimplification in planar tiles. 66 | * @param minFeaturePolylineSize Minimum number of connected edges in a sharp feature polyline to consider it during processing 67 | * @param maxClusterSize Maximum cluster size per zoom 68 | * @param maxSurfaceVariance Maximum cluster variation value per zoom 69 | */ 70 | TinCreationSimplificationPointSetHierarchy(const std::vector& borderSimplificationMaxDistancePerZoom, 71 | const std::vector& borderSimplificationMaxLengthPerZoom, 72 | unsigned int minFeaturePolylineSize, 73 | const std::vector& maxClusterSizePerZoom, 74 | const std::vector& maxSurfaceVariancePerZoom) 75 | : TinCreationSimplificationPointSet(borderSimplificationMaxDistancePerZoom, 76 | borderSimplificationMaxLengthPerZoom, 77 | minFeaturePolylineSize) 78 | , m_maxClusterSizePerZoom(maxClusterSizePerZoom) 79 | , m_maxSurfaceVariancePerZoom(maxSurfaceVariancePerZoom) 80 | { 81 | setParamsForZoomConcreteStrategy(0); 82 | } 83 | 84 | std::vector simplify(const std::vector& pts); 85 | 86 | void setParamsForZoomConcreteStrategy(const unsigned int& zoom) { 87 | m_maxClusterSize = standardHandlingOfThresholdPerZoom(m_maxClusterSizePerZoom, zoom); 88 | m_maxSurfaceVariance = standardHandlingOfThresholdPerZoom(m_maxSurfaceVariancePerZoom, zoom); 89 | } 90 | 91 | private: 92 | unsigned int m_maxClusterSize; 93 | double m_maxSurfaceVariance; 94 | std::vector m_maxClusterSizePerZoom; 95 | std::vector m_maxSurfaceVariancePerZoom; 96 | }; 97 | 98 | } // End namespace TinCreation 99 | 100 | #endif //EMODNET_QMGC_TIN_CREATION_SIMPLIFICATION_POINT_SET_HIERARCHY_H 101 | -------------------------------------------------------------------------------- /src/tin_creation/tin_creation_simplification_point_set_random.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Coronis Computing S.L. (Spain) 2 | // All rights reserved. 3 | // 4 | // This file is part of EMODnet Quantized Mesh Generator for Cesium. 5 | // 6 | // This program is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | // Author: Ricard Campos (ricardcd@gmail.com) 20 | 21 | #include "tin_creation_simplification_point_set_random.h" 22 | #include 23 | 24 | namespace TinCreation { 25 | 26 | std::vector 27 | TinCreationSimplificationPointSetRandom:: 28 | simplify(const std::vector &pts) { 29 | std::vector ptsSimp = pts; 30 | 31 | // Simplify using random simplification (erase-remove idiom) 32 | ptsSimp.erase(CGAL::random_simplify_point_set(ptsSimp.begin(), 33 | ptsSimp.end(), 34 | m_removePercentage), 35 | ptsSimp.end()); 36 | 37 | return ptsSimp; 38 | } 39 | 40 | } // End namespace TinCreation -------------------------------------------------------------------------------- /src/tin_creation/tin_creation_simplification_point_set_random.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Coronis Computing S.L. (Spain) 2 | // All rights reserved. 3 | // 4 | // This file is part of EMODnet Quantized Mesh Generator for Cesium. 5 | // 6 | // This program is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | // Author: Ricard Campos (ricardcd@gmail.com) 20 | 21 | #ifndef EMODNET_QMGC_TIN_CREATION_SIMPLIFICATION_POINT_SET_RANDOM_H 22 | #define EMODNET_QMGC_TIN_CREATION_SIMPLIFICATION_POINT_SET_RANDOM_H 23 | 24 | #include "tin_creation_simplification_point_set.h" 25 | #include "tin_creation_utils.h" 26 | 27 | namespace TinCreation { 28 | 29 | /** 30 | * @class TinCreationSimplificationPointSetRandom 31 | * @brief Creates a TIN using a random simplification 32 | * 33 | * It basically selects randomly a given subset of the original points. 34 | */ 35 | class TinCreationSimplificationPointSetRandom 36 | : public TinCreationSimplificationPointSet { 37 | public: 38 | 39 | /** 40 | * Constructor 41 | * @param borderSimplificationMaxDistance Maximum error for polyline simplification 42 | * @param borderSimplificationMaxLengthPercent Maximum length for an edge in the simplified polyline. This prevents oversimplification in planar tiles. 43 | * @param minFeaturePolylineSize Minimum number of connected edges in a sharp feature polyline to consider it during processing 44 | * @param removePercentage Percentage of points to remove from the input set 45 | */ 46 | TinCreationSimplificationPointSetRandom(double borderSimplificationMaxDistance, 47 | double borderSimplificationMaxLength, 48 | unsigned int minFeaturePolylineSize, 49 | double removePercentage) 50 | : TinCreationSimplificationPointSet(borderSimplificationMaxDistance, 51 | borderSimplificationMaxLength, 52 | minFeaturePolylineSize) 53 | { 54 | m_removePercentagePerZoom = std::vector{removePercentage}; 55 | setParamsForZoomConcreteStrategy(0); 56 | } 57 | 58 | /** 59 | * Constructor 60 | * @param borderSimplificationMaxDistance Maximum error for polyline simplification per zoom 61 | * @param borderSimplificationMaxLengthPercent Maximum length for an edge in the simplified polyline per zoom. This prevents oversimplification in planar tiles. 62 | * @param minFeaturePolylineSize Minimum number of connected edges in a sharp feature polyline to consider it during processing 63 | * @param removePercentage Percentage of points to remove from the input set per zoom 64 | */ 65 | TinCreationSimplificationPointSetRandom(std::vector borderSimplificationMaxDistancePerZoom, 66 | std::vector borderSimplificationMaxLengthPerZoom, 67 | unsigned int minFeaturePolylineSize, 68 | std::vector removePercentagePerZoom) 69 | : TinCreationSimplificationPointSet(borderSimplificationMaxDistancePerZoom, 70 | borderSimplificationMaxLengthPerZoom, 71 | minFeaturePolylineSize) 72 | , m_removePercentagePerZoom(removePercentagePerZoom) 73 | { 74 | setParamsForZoomConcreteStrategy(0); 75 | } 76 | 77 | std::vector simplify(const std::vector &pts); 78 | 79 | void setParamsForZoomConcreteStrategy(const unsigned int& zoom) { 80 | m_removePercentage = standardHandlingOfThresholdPerZoom(m_removePercentagePerZoom, zoom); 81 | } 82 | 83 | private: 84 | // --- Attributes --- 85 | double m_removePercentage; 86 | std::vector m_removePercentagePerZoom; 87 | }; 88 | 89 | } // End namespace TinCreation 90 | 91 | #endif //EMODNET_QMGC_TIN_CREATION_SIMPLIFICATION_POINT_SET_RANDOM_H 92 | -------------------------------------------------------------------------------- /src/tin_creation/tin_creation_simplification_point_set_wlop.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Coronis Computing S.L. (Spain) 2 | // All rights reserved. 3 | // 4 | // This file is part of EMODnet Quantized Mesh Generator for Cesium. 5 | // 6 | // This program is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | // Author: Ricard Campos (ricardcd@gmail.com) 20 | 21 | #include "tin_creation_simplification_point_set_wlop.h" 22 | #include 23 | 24 | namespace TinCreation { 25 | 26 | std::vector 27 | TinCreationSimplificationPointSetWLOP:: 28 | simplify(const std::vector &pts) { 29 | // Convert to metric 30 | std::vector ptsToSimpECEF = this->convertUVHToECEF(pts); 31 | 32 | std::vector ptsSimpECEF; 33 | CGAL::wlop_simplify_and_regularize_point_set 34 | 35 | (ptsToSimpECEF.begin(), 36 | ptsToSimpECEF.end(), 37 | std::back_inserter(ptsSimpECEF), 38 | m_retainPercentage, 39 | m_radius 40 | ); 41 | 42 | // Convert to the local (XY-projectable) coordinates again 43 | std::vector ptsSimp = this->convertECEFToUVH(ptsSimpECEF); 44 | 45 | return ptsSimp; 46 | } 47 | 48 | } // End namespace TinCreation -------------------------------------------------------------------------------- /src/tin_creation/tin_creation_simplification_point_set_wlop.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Coronis Computing S.L. (Spain) 2 | // All rights reserved. 3 | // 4 | // This file is part of EMODnet Quantized Mesh Generator for Cesium. 5 | // 6 | // This program is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | // Author: Ricard Campos (ricardcd@gmail.com) 20 | 21 | #ifndef EMODNET_QMGC_TIN_CREATION_SIMPLIFICATION_POINT_SET_WLOP_H 22 | #define EMODNET_QMGC_TIN_CREATION_SIMPLIFICATION_POINT_SET_WLOP_H 23 | 24 | #include "tin_creation_simplification_point_set.h" 25 | 26 | namespace TinCreation { 27 | 28 | /** 29 | * @class TinCreationSimplificationPointSetWLOP 30 | * @brief Creates a TIN using the Weighted Locally Optimal Projection (WLOP) algorithm 31 | * 32 | * We use the implementation of WLOP on the CGAL libraries, which are based on the following paper:
33 | * H. Huang, D. Li, H. Zhang, U. Ascher, and D. Cohen-Or. Consolidation of unorganized point clouds for surface reconstruction. ACM Transactions on Graphics, 28:176:1–176:78, 2009. 34 | */ 35 | class TinCreationSimplificationPointSetWLOP 36 | : public TinCreationSimplificationPointSet 37 | { 38 | public: 39 | /** 40 | * Constructor 41 | * @param borderSimplificationMaxDistance Maximum error for polyline simplification 42 | * @param borderSimplificationMaxLengthPercent Maximum length for an edge in the simplified polyline. This prevents oversimplification in planar tiles. 43 | * @param minFeaturePolylineSize Minimum number of connected edges in a sharp feature polyline to consider it during processing 44 | * @param retainPercentage Percentage of points to retain 45 | * @param radius Spherical neighborhood radius 46 | * @param iterNumber Number of iterations to solve the optimization problem 47 | */ 48 | TinCreationSimplificationPointSetWLOP(double borderSimplificationMaxDistance, 49 | double borderSimplificationMaxLength, 50 | unsigned int minFeaturePolylineSize, 51 | double retainPercentage, 52 | double radius, 53 | unsigned int iterNumber = 35) 54 | : TinCreationSimplificationPointSet(borderSimplificationMaxDistance, borderSimplificationMaxLength, minFeaturePolylineSize) 55 | , m_iterNumber(iterNumber) 56 | { 57 | m_retainPercentagePerZoom = std::vector{retainPercentage}; 58 | m_radiusPerZoom = std::vector{radius}; 59 | setParamsForZoomConcreteStrategy(0); 60 | } 61 | 62 | /** 63 | * Constructor 64 | * @param borderSimplificationMaxDistance Maximum error for polyline simplification per zoom 65 | * @param borderSimplificationMaxLengthPercent Maximum length for an edge in the simplified polyline per zoom. This prevents oversimplification in planar tiles. 66 | * @param minFeaturePolylineSize Minimum number of connected edges in a sharp feature polyline to consider it during processing 67 | * @param retainPercentage Percentage of points to retain per zoom 68 | * @param radius Spherical neighborhood radius per zoom 69 | * @param iterNumber Number of iterations to solve the optimization problem per zoom 70 | */ 71 | TinCreationSimplificationPointSetWLOP(std::vector borderSimplificationMaxDistancePerZoom, 72 | std::vector borderSimplificationMaxLengthPerZoom, 73 | unsigned int minFeaturePolylineSize, 74 | std::vector retainPercentagePerZoom, 75 | std::vector radiusPerZoom, 76 | unsigned int iterNumber = 35) 77 | : TinCreationSimplificationPointSet(borderSimplificationMaxDistancePerZoom, 78 | borderSimplificationMaxLengthPerZoom, 79 | minFeaturePolylineSize) 80 | , m_retainPercentagePerZoom(retainPercentagePerZoom) 81 | , m_radiusPerZoom(radiusPerZoom) 82 | , m_iterNumber(iterNumber) 83 | { 84 | setParamsForZoomConcreteStrategy(0); 85 | } 86 | 87 | std::vector simplify(const std::vector& pts); 88 | 89 | void setParamsForZoomConcreteStrategy(const unsigned int& zoom) { 90 | m_retainPercentage = standardHandlingOfThresholdPerZoom(m_retainPercentagePerZoom, zoom, false); 91 | m_radius = standardHandlingOfThresholdPerZoom(m_radiusPerZoom, zoom); 92 | } 93 | 94 | private: 95 | // --- Attributes --- 96 | double m_retainPercentage; 97 | double m_radius; 98 | unsigned int m_iterNumber; 99 | std::vector m_retainPercentagePerZoom; // percentage of points to retain. 100 | std::vector m_radiusPerZoom; // neighbors size. 101 | }; 102 | 103 | } // End namespace TinCreation 104 | 105 | #endif //EMODNET_QMGC_TIN_CREATION_SIMPLIFICATION_POINT_SET_WLOP_H 106 | -------------------------------------------------------------------------------- /src/tin_creation/tin_creation_utils.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Coronis Computing S.L. (Spain) 2 | // All rights reserved. 3 | // 4 | // This file is part of EMODnet Quantized Mesh Generator for Cesium. 5 | // 6 | // This program is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | // Author: Ricard Campos (ricardcd@gmail.com) 20 | 21 | #ifndef EMODNET_QMGC_TIN_CREATION_UTILS_H 22 | #define EMODNET_QMGC_TIN_CREATION_UTILS_H 23 | 24 | #include 25 | #include 26 | 27 | namespace TinCreation { 28 | 29 | /** 30 | * Some of the parameters are scale-dependant and, as such, they should depend on the zoom level of the pyramid. 31 | * If we refer to a parameter for a zoom z as p_z, we allow the user to just set p_z and then we compute the values for other zooms as p_z = p_0/2^z, for those parameters whose scale needs to be lowered at deeper levels, or p_z = p_0*2^z, for those whose scale needs to grow with depth. 32 | * The parameters marked with an asterisk (*) in the help of `qm_tiler` are using the setting proposed here. 33 | * Basically, depending on the number of values in the \p thresholdsPerZoom vector, we can: 34 | * * Set a single value: In this case, the value represents p_0, and the rest of values for the deeper zooms will be computed using the formulas presented in the previous paragraph. 35 | * * Set multiple values (by entering the same parameter more than once): In this way we can set a parameter for each zoom. If the user inputs less parameters than the number of required zoom levels, the last value is used for all the rest of deeper zooms to create. 36 | * @tparam T Numeric type of the parameter 37 | * @param thresholdsPerZoom Vector of thresholds per zoom. As explained above, it may contain a single parameter also. 38 | * @param zoom Current zoom level. 39 | * @param downScale Flag indicating whether the value of the parameter should be downScaled with zoom or, otherwise, upscaled 40 | * @return 41 | */ 42 | template 43 | T standardHandlingOfThresholdPerZoom(const std::vector& thresholdsPerZoom, 44 | const unsigned int& zoom, 45 | const bool& downScale = true) 46 | { 47 | T thres; 48 | if (thresholdsPerZoom.size() == 1) { 49 | // This means that only the root tolerance was specified, we will infer the tolerance at the desired zoom level by dividing by two the root number for each level 50 | if (zoom == 0) 51 | thres = thresholdsPerZoom[0]; 52 | else { 53 | if (downScale) 54 | thres = thresholdsPerZoom[0] / pow(2.0, zoom); 55 | else 56 | thres = thresholdsPerZoom[0] * pow(2.0, zoom); 57 | } 58 | } else if (zoom < thresholdsPerZoom.size()) { 59 | // Use the approximation tolerance corresponding to the zoom in the vector 60 | thres = thresholdsPerZoom[zoom]; 61 | } else { 62 | // Use the approximation tolerance corresponding to the last zoom specified in the vector 63 | thres = thresholdsPerZoom.back(); 64 | } 65 | 66 | return thres; 67 | } 68 | 69 | 70 | } // End namespace TinCreation 71 | 72 | #endif //EMODNET_QMGC_TIN_CREATION_UTILS_H 73 | -------------------------------------------------------------------------------- /src/tin_creation/tin_creator.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Coronis Computing S.L. (Spain) 2 | // All rights reserved. 3 | // 4 | // This file is part of EMODnet Quantized Mesh Generator for Cesium. 5 | // 6 | // This program is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | // Author: Ricard Campos (ricardcd@gmail.com) 20 | 21 | #include "tin_creator.h" 22 | #include "crs_conversions.h" 23 | 24 | namespace TinCreation { 25 | 26 | std::vector 27 | TinCreationStrategy:: 28 | convertUVHToECEF(const std::vector &pts) const { 29 | if (!this->hasOriginalBoundingBox()) { 30 | // The limits were not set, probably because the input to decimate is a mesh, and the scale is supposed to be metric already 31 | return pts; 32 | } 33 | 34 | // Points in ECEF coordinates 35 | std::vector ecefPoints; 36 | ecefPoints.reserve(pts.size()); 37 | for (std::vector::const_iterator it = pts.begin(); it != pts.end(); ++it) { 38 | ecefPoints.emplace_back(convertUVHToECEF(*it)); 39 | } 40 | 41 | return ecefPoints; 42 | } 43 | 44 | 45 | std::vector 46 | TinCreationStrategy:: 47 | convertECEFToUVH(const std::vector &pts) const { 48 | if (!this->hasOriginalBoundingBox()) { 49 | // The limits were not set, probably because the input to decimate is a mesh, and the scale is supposed to be metric already 50 | return pts; 51 | } 52 | 53 | // Points in ECEF coordinates 54 | std::vector uvhPoints; 55 | uvhPoints.reserve(pts.size()); 56 | for (std::vector::const_iterator it = pts.begin(); it != pts.end(); ++it) { 57 | uvhPoints.emplace_back(convertECEFToUVH(*it)); 58 | } 59 | 60 | return uvhPoints; 61 | } 62 | 63 | Point_3 TinCreationStrategy::convertUVHToECEF(const Point_3& p) const 64 | { 65 | if (!this->hasOriginalBoundingBox()) { 66 | // The limits were not set, probably because the input to decimate is a mesh, and the scale is supposed to be metric already 67 | return p; 68 | } 69 | 70 | // From UVH to lat/lon/height 71 | double lat = this->getMinY() + ((this->getMaxY() - this->getMinY()) * p.y()); 72 | double lon = this->getMinX() + ((this->getMaxX() - this->getMinX()) * p.x()); 73 | double h = this->getMinZ() + ((this->getMaxZ() - this->getMinZ()) * p.z()); 74 | 75 | double tmpx, tmpy, tmpz; 76 | crs_conversions::llh2ecef(lat, lon, h, 77 | tmpx, tmpy, tmpz); 78 | 79 | return Point_3(tmpx, tmpy, tmpz); 80 | } 81 | 82 | /// Convert points from local UVH to ECEF given the limits of the tile 83 | // This conversion is used by some point set simplification methods requiring metric coordinates 84 | Point_3 TinCreationStrategy::convertECEFToUVH(const Point_3& p) const 85 | { 86 | if (!this->hasOriginalBoundingBox()) { 87 | // The limits were not set, probably because the input to decimate is a mesh, and the scale is supposed to be metric already 88 | return p; 89 | } 90 | 91 | // From ECEF to lat/lon/height 92 | double lat, lon, height; 93 | crs_conversions::ecef2llh(p.x(), p.y(), p.z(), 94 | lat, lon, height); 95 | 96 | // Scale to local U/V/H 97 | double u = (lon - this->getMinX()) / (this->getMaxX() - this->getMinX()); 98 | double v = (lat - this->getMinY()) / (this->getMaxY() - this->getMinY()); 99 | double h = (this->getMaxZ() - this->getMinZ()) < std::numeric_limits::epsilon() 100 | ? // Avoid division by 0 ((this->getMaxZ() - this->getMinZ()) == 0 in flat tiles!) 101 | height - this->getMinZ() 102 | : (height - this->getMinZ()) / (this->getMaxZ() - this->getMinZ()); 103 | 104 | return Point_3(u, v, h); 105 | } 106 | 107 | } // End namespace TinCreation --------------------------------------------------------------------------------