| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /* | ||
| 2 | * Copyright (c) 2000-2022 Inria | ||
| 3 | * All rights reserved. | ||
| 4 | * | ||
| 5 | * Redistribution and use in source and binary forms, with or without | ||
| 6 | * modification, are permitted provided that the following conditions are met: | ||
| 7 | * | ||
| 8 | * * Redistributions of source code must retain the above copyright notice, | ||
| 9 | * this list of conditions and the following disclaimer. | ||
| 10 | * * Redistributions in binary form must reproduce the above copyright notice, | ||
| 11 | * this list of conditions and the following disclaimer in the documentation | ||
| 12 | * and/or other materials provided with the distribution. | ||
| 13 | * * Neither the name of the ALICE Project-Team nor the names of its | ||
| 14 | * contributors may be used to endorse or promote products derived from this | ||
| 15 | * software without specific prior written permission. | ||
| 16 | * | ||
| 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
| 18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
| 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
| 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | ||
| 21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
| 22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
| 23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||
| 24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||
| 25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
| 26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
| 27 | * POSSIBILITY OF SUCH DAMAGE. | ||
| 28 | * | ||
| 29 | * Contact: Bruno Levy | ||
| 30 | * | ||
| 31 | * https://www.inria.fr/fr/bruno-levy | ||
| 32 | * | ||
| 33 | * Inria, | ||
| 34 | * Domaine de Voluceau, | ||
| 35 | * 78150 Le Chesnay - Rocquencourt | ||
| 36 | * FRANCE | ||
| 37 | * | ||
| 38 | */ | ||
| 39 | |||
| 40 | #include <geogram/mesh/mesh_io.h> | ||
| 41 | #include <geogram/mesh/mesh.h> | ||
| 42 | #include <geogram/mesh/mesh_repair.h> | ||
| 43 | #include <geogram/mesh/index.h> | ||
| 44 | #include <geogram/points/colocate.h> | ||
| 45 | #include <geogram/basic/line_stream.h> | ||
| 46 | #include <geogram/basic/b_stream.h> | ||
| 47 | #include <geogram/basic/geofile.h> | ||
| 48 | #include <geogram/basic/file_system.h> | ||
| 49 | #include <geogram/basic/command_line.h> | ||
| 50 | #include <geogram/basic/argused.h> | ||
| 51 | #include <geogram/basic/logger.h> | ||
| 52 | #include <geogram/basic/geometry.h> | ||
| 53 | #include <geogram/bibliography/bibliography.h> | ||
| 54 | |||
| 55 | #include <fstream> | ||
| 56 | |||
| 57 | #ifdef GEOGRAM_USE_BUILTIN_DEPS | ||
| 58 | extern "C" { | ||
| 59 | #include <geogram/third_party/libMeshb/sources/libmeshb7.h> | ||
| 60 | } | ||
| 61 | #include <geogram/third_party/rply/rply.h> | ||
| 62 | #else | ||
| 63 | extern "C" { | ||
| 64 | #include <libmeshb7.h> | ||
| 65 | } | ||
| 66 | #include <rply.h> | ||
| 67 | #endif | ||
| 68 | |||
| 69 | #ifdef GEO_COMPILER_GCC | ||
| 70 | #include <cxxabi.h> | ||
| 71 | namespace { | ||
| 72 | ✗ | std::string demangle(const std::string& mangled) { | |
| 73 | int status; | ||
| 74 | char* realname = | ||
| 75 | ✗ | abi::__cxa_demangle(mangled.c_str(), nullptr, nullptr, &status); | |
| 76 | ✗ | std::string result(realname); | |
| 77 | ✗ | free(realname); | |
| 78 | ✗ | return result; | |
| 79 | } | ||
| 80 | } | ||
| 81 | #else | ||
| 82 | namespace { | ||
| 83 | std::string demangle(const std::string& mangled) { | ||
| 84 | return mangled; | ||
| 85 | } | ||
| 86 | } | ||
| 87 | #endif | ||
| 88 | |||
| 89 | // TODO: take into account selected mesh elements | ||
| 90 | // in loaders and exporters. | ||
| 91 | |||
| 92 | // We got some IOHandler classes declared locally that | ||
| 93 | // have no out-of-line virtual functions. It is not a | ||
| 94 | // problem since they are only visible from this translation | ||
| 95 | // unit, but clang will complain. | ||
| 96 | #ifdef __clang__ | ||
| 97 | #pragma GCC diagnostic ignored "-Wweak-vtables" | ||
| 98 | #endif | ||
| 99 | |||
| 100 | namespace GEO { | ||
| 101 | |||
| 102 | 482359 | inline void set_mesh_point( | |
| 103 | Mesh& M, index_t v, const double* coords, index_t dim | ||
| 104 | ) { | ||
| 105 |
1/6✗ Branch 1 not taken.
✓ Branch 2 taken 482359 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
|
482359 | geo_debug_assert(M.vertices.dimension() >= dim); |
| 106 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 482359 times.
|
482359 | if(M.vertices.single_precision()) { |
| 107 | ✗ | float* p = M.vertices.single_precision_point_ptr(v); | |
| 108 | ✗ | for(index_t c=0; c<dim; ++c) { | |
| 109 | ✗ | p[c] = float(coords[c]); | |
| 110 | } | ||
| 111 | } else { | ||
| 112 | 482359 | double* p = M.vertices.point_ptr(v); | |
| 113 |
2/2✓ Branch 0 taken 1449577 times.
✓ Branch 1 taken 482359 times.
|
1931936 | for(index_t c=0; c<dim; ++c) { |
| 114 | 1449577 | p[c] = coords[c]; | |
| 115 | } | ||
| 116 | } | ||
| 117 | 482359 | } | |
| 118 | |||
| 119 | 55506 | inline void set_mesh_point( | |
| 120 | Mesh& M, index_t v, const float* coords, index_t dim | ||
| 121 | ) { | ||
| 122 |
1/6✗ Branch 1 not taken.
✓ Branch 2 taken 55506 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
|
55506 | geo_debug_assert(M.vertices.dimension() >= dim); |
| 123 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 55506 times.
|
55506 | if(M.vertices.single_precision()) { |
| 124 | ✗ | float* p = M.vertices.single_precision_point_ptr(v); | |
| 125 | ✗ | for(index_t c=0; c<dim; ++c) { | |
| 126 | ✗ | p[c] = coords[c]; | |
| 127 | } | ||
| 128 | } else { | ||
| 129 | 55506 | double* p = M.vertices.point_ptr(v); | |
| 130 |
2/2✓ Branch 0 taken 166518 times.
✓ Branch 1 taken 55506 times.
|
222024 | for(index_t c=0; c<dim; ++c) { |
| 131 | 166518 | p[c] = double(coords[c]); | |
| 132 | } | ||
| 133 | } | ||
| 134 | 55506 | } | |
| 135 | |||
| 136 | |||
| 137 | 449229 | inline void get_mesh_point( | |
| 138 | const Mesh& M, index_t v, double* coords, index_t dim | ||
| 139 | ) { | ||
| 140 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 449229 times.
|
449229 | if(M.vertices.single_precision()) { |
| 141 | ✗ | const float* p = M.vertices.single_precision_point_ptr(v); | |
| 142 | ✗ | for(index_t c=0; c<dim; ++c) { | |
| 143 | ✗ | coords[c] = (c < M.vertices.dimension()) ? double(p[c]) : 0.0; | |
| 144 | } | ||
| 145 | } else { | ||
| 146 | 449229 | const double* p = M.vertices.point_ptr(v); | |
| 147 |
2/2✓ Branch 0 taken 1347687 times.
✓ Branch 1 taken 449229 times.
|
1796916 | for(index_t c=0; c<dim; ++c) { |
| 148 |
1/2✓ Branch 1 taken 1347687 times.
✗ Branch 2 not taken.
|
1347687 | coords[c] = (c < M.vertices.dimension()) ? p[c] : 0.0; |
| 149 | } | ||
| 150 | } | ||
| 151 | 449229 | } | |
| 152 | |||
| 153 | /************************************************************************/ | ||
| 154 | |||
| 155 | /** | ||
| 156 | * \brief IO handler for AliasWavefront OBJ format. | ||
| 157 | * \see http://en.wikipedia.org/wiki/Wavefront_.obj_file | ||
| 158 | */ | ||
| 159 | class GEOGRAM_API OBJIOHandler : public MeshIOHandler { | ||
| 160 | public: | ||
| 161 | /** | ||
| 162 | * \brief Creates a OBJ IO handler. | ||
| 163 | * \param[in] dimension dimension of the vertices | ||
| 164 | * (3 for regular 3d mesh) | ||
| 165 | */ | ||
| 166 | 227 | OBJIOHandler(coord_index_t dimension = 3) : | |
| 167 |
2/4✓ Branch 2 taken 227 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 227 times.
✗ Branch 6 not taken.
|
227 | dimension_(dimension) { |
| 168 | 227 | } | |
| 169 | |||
| 170 | 168 | bool load( | |
| 171 | const std::string& filename, Mesh& M, | ||
| 172 | const MeshIOFlags& ioflags | ||
| 173 | ) override { | ||
| 174 | 168 | bool ignore_tex_coords = false; | |
| 175 | //!ioflags.has_attribute(MESH_VERTEX_TEX_COORD); | ||
| 176 | |||
| 177 | 168 | vector<vec2> tex_vertices; | |
| 178 |
1/2✓ Branch 1 taken 168 times.
✗ Branch 2 not taken.
|
168 | Attribute<double> tex_coord; |
| 179 |
1/2✓ Branch 1 taken 168 times.
✗ Branch 2 not taken.
|
168 | vector<double> P(dimension_); |
| 180 |
2/4✓ Branch 1 taken 168 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 168 times.
|
168 | if(M.vertices.dimension() != dimension_) { |
| 181 | ✗ | M.vertices.set_dimension(dimension_); | |
| 182 | } | ||
| 183 | |||
| 184 |
1/2✓ Branch 1 taken 168 times.
✗ Branch 2 not taken.
|
168 | LineInput in(filename); |
| 185 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 167 times.
|
168 | if(!in.OK()) { |
| 186 | 1 | return false; | |
| 187 | } | ||
| 188 | |||
| 189 |
1/2✓ Branch 1 taken 167 times.
✗ Branch 2 not taken.
|
167 | bind_attributes(M, ioflags, true); |
| 190 | 167 | vector<index_t> facet_vertices; | |
| 191 | 167 | vector<index_t> facet_tex_vertices; | |
| 192 | |||
| 193 | 167 | bool first_facet_attribute = true; | |
| 194 | 167 | bool read_facet_regions = false; | |
| 195 |
6/8✓ Branch 1 taken 763934 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 763934 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 763770 times.
✓ Branch 7 taken 164 times.
✓ Branch 8 taken 763770 times.
✓ Branch 9 taken 164 times.
|
764101 | while(!in.eof() && in.get_line()) { |
| 196 |
1/2✓ Branch 1 taken 763770 times.
✗ Branch 2 not taken.
|
763770 | in.get_fields(); |
| 197 |
1/2✓ Branch 1 taken 763770 times.
✗ Branch 2 not taken.
|
763770 | if(in.nb_fields() >= 1) { |
| 198 |
3/4✓ Branch 1 taken 763770 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 345174 times.
✓ Branch 4 taken 418596 times.
|
763770 | if(in.field_matches(0, "v")) { |
| 199 |
2/2✓ Branch 0 taken 1035520 times.
✓ Branch 1 taken 345173 times.
|
1380693 | for(coord_index_t c = 0; c < dimension_; c++) { |
| 200 |
1/2✓ Branch 1 taken 1035520 times.
✗ Branch 2 not taken.
|
1035520 | if(index_t(c + 1) < in.nb_fields()) { |
| 201 |
3/4✓ Branch 1 taken 1035519 times.
✓ Branch 2 taken 1 times.
✓ Branch 4 taken 1035519 times.
✗ Branch 5 not taken.
|
1035520 | P[c] = in.field_as_double(index_t(c + 1)); |
| 202 | } else { | ||
| 203 | ✗ | P[c] = 0.0; | |
| 204 | } | ||
| 205 | } | ||
| 206 |
1/2✓ Branch 1 taken 345173 times.
✗ Branch 2 not taken.
|
345173 | index_t v = M.vertices.create_vertex(); |
| 207 |
1/2✓ Branch 2 taken 345173 times.
✗ Branch 3 not taken.
|
345173 | set_mesh_point(M, v, P.data(), dimension_); |
| 208 | 418596 | } else if( | |
| 209 |
3/4✓ Branch 0 taken 418596 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 203903 times.
✓ Branch 3 taken 214693 times.
|
837192 | !ignore_tex_coords && |
| 210 |
3/4✓ Branch 1 taken 418596 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 203903 times.
✓ Branch 4 taken 214693 times.
|
418596 | in.field_matches(0, "vt") |
| 211 | ) { | ||
| 212 |
2/2✓ Branch 1 taken 115 times.
✓ Branch 2 taken 203788 times.
|
203903 | if(!tex_coord_.is_bound()) { |
| 213 |
1/2✓ Branch 2 taken 115 times.
✗ Branch 3 not taken.
|
230 | tex_coord_.bind_if_is_defined( |
| 214 |
1/2✓ Branch 1 taken 115 times.
✗ Branch 2 not taken.
|
230 | M.facet_corners.attributes(), "tex_coord" |
| 215 | ); | ||
| 216 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 115 times.
|
115 | if(tex_coord.is_bound()) { |
| 217 | ✗ | if(tex_coord_.dimension() != 2) { | |
| 218 | ✗ | tex_coord_.unbind(); | |
| 219 | ✗ | ignore_tex_coords = true; | |
| 220 | } | ||
| 221 | } else { | ||
| 222 |
1/2✓ Branch 2 taken 115 times.
✗ Branch 3 not taken.
|
230 | tex_coord_.create_vector_attribute( |
| 223 |
1/2✓ Branch 1 taken 115 times.
✗ Branch 2 not taken.
|
345 | M.facet_corners.attributes(), "tex_coord", 2 |
| 224 | ); | ||
| 225 | } | ||
| 226 | } | ||
| 227 | |||
| 228 |
1/2✓ Branch 0 taken 203903 times.
✗ Branch 1 not taken.
|
203903 | if(!ignore_tex_coords) { |
| 229 | 203903 | if( | |
| 230 |
2/6✗ Branch 1 not taken.
✓ Branch 2 taken 203903 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 203903 times.
|
203903 | in.nb_fields() != 3 && |
| 231 | ✗ | in.nb_fields() != 4 // TODO: read 3D UVs ? | |
| 232 | ) { | ||
| 233 | ✗ | Logger::err("I/O") | |
| 234 | ✗ | << "Line " << in.line_number() | |
| 235 | ✗ | << " malformed texture vertex" | |
| 236 | ✗ | << std::endl; | |
| 237 | ✗ | unbind_attributes(); | |
| 238 | ✗ | return false; | |
| 239 | } | ||
| 240 |
1/2✓ Branch 1 taken 203903 times.
✗ Branch 2 not taken.
|
203903 | tex_vertices.push_back( |
| 241 | ✗ | vec2( | |
| 242 | ✗ | in.field_as_double(1), | |
| 243 |
2/4✓ Branch 1 taken 203903 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 203903 times.
✗ Branch 5 not taken.
|
407806 | in.field_as_double(2)) |
| 244 | ); | ||
| 245 | } | ||
| 246 | 214693 | } else if( | |
| 247 |
3/4✓ Branch 1 taken 214693 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 854 times.
✓ Branch 4 taken 213839 times.
|
429386 | ioflags.has_element(MESH_EDGES) && |
| 248 |
3/4✓ Branch 1 taken 214693 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 854 times.
✓ Branch 4 taken 213839 times.
|
214693 | in.field_matches(0, "l") |
| 249 | ) { | ||
| 250 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 854 times.
|
854 | if(in.nb_fields() < 2) { |
| 251 | ✗ | Logger::err("I/O") | |
| 252 | ✗ | << "Line " << in.line_number() | |
| 253 | ✗ | << ": polyline only has " << in.nb_fields() | |
| 254 | ✗ | << " vertices (at least 2 required)" | |
| 255 | ✗ | << std::endl; | |
| 256 | ✗ | unbind_attributes(); | |
| 257 | ✗ | return false; | |
| 258 | } | ||
| 259 | 854 | index_t prev = NO_INDEX; | |
| 260 |
2/2✓ Branch 1 taken 1708 times.
✓ Branch 2 taken 854 times.
|
2562 | for(index_t i=1; i<in.nb_fields(); ++i) { |
| 261 | signed_index_t s_vertex_index = | ||
| 262 |
1/2✓ Branch 1 taken 1708 times.
✗ Branch 2 not taken.
|
1708 | in.field_as_int(i); |
| 263 | 1708 | index_t vertex_index = 0; | |
| 264 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1708 times.
|
1708 | if(s_vertex_index < 0) { |
| 265 | ✗ | vertex_index = index_t( | |
| 266 | ✗ | 1+int(M.vertices.nb()) + s_vertex_index | |
| 267 | ); | ||
| 268 | } else { | ||
| 269 | 1708 | vertex_index = index_t(s_vertex_index); | |
| 270 | } | ||
| 271 | 1708 | if( | |
| 272 |
3/6✓ Branch 0 taken 1708 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1708 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1708 times.
|
3416 | (vertex_index < 1) || |
| 273 | 1708 | (vertex_index > M.vertices.nb()) | |
| 274 | ) { | ||
| 275 | ✗ | Logger::err("I/O") | |
| 276 | ✗ | << "Line " << in.line_number() | |
| 277 | ✗ | << ": line vertex #" << i | |
| 278 | ✗ | << " references an invalid vertex: " | |
| 279 | ✗ | << vertex_index | |
| 280 | ✗ | << std::endl; | |
| 281 | ✗ | unbind_attributes(); | |
| 282 | ✗ | return false; | |
| 283 | } | ||
| 284 |
2/2✓ Branch 0 taken 854 times.
✓ Branch 1 taken 854 times.
|
1708 | if(prev != NO_INDEX) { |
| 285 |
1/2✓ Branch 1 taken 854 times.
✗ Branch 2 not taken.
|
854 | M.edges.create_edge(prev-1,vertex_index-1); |
| 286 | } | ||
| 287 | 1708 | prev = vertex_index; | |
| 288 | } | ||
| 289 | 213839 | } else if( | |
| 290 |
4/4✓ Branch 1 taken 213815 times.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 200604 times.
✓ Branch 4 taken 13235 times.
|
427654 | ioflags.has_element(MESH_FACETS) && |
| 291 |
3/4✓ Branch 1 taken 213815 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 200604 times.
✓ Branch 4 taken 13211 times.
|
213815 | in.field_matches(0, "f") |
| 292 | ) { | ||
| 293 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 200604 times.
|
200604 | if(in.nb_fields() < 3) { |
| 294 | ✗ | Logger::err("I/O") | |
| 295 | ✗ | << "Line " << in.line_number() | |
| 296 | ✗ | << ": facet only has " << in.nb_fields() | |
| 297 | ✗ | << " corners (at least 3 required)" | |
| 298 | ✗ | << std::endl; | |
| 299 | ✗ | unbind_attributes(); | |
| 300 | ✗ | return false; | |
| 301 | } | ||
| 302 | |||
| 303 |
1/2✓ Branch 1 taken 200604 times.
✗ Branch 2 not taken.
|
200604 | facet_vertices.resize(0); |
| 304 |
1/2✓ Branch 1 taken 200604 times.
✗ Branch 2 not taken.
|
200604 | facet_tex_vertices.resize(0); |
| 305 | |||
| 306 |
2/2✓ Branch 1 taken 640346 times.
✓ Branch 2 taken 200602 times.
|
840948 | for(index_t i = 1; i < in.nb_fields(); i++) { |
| 307 | 640346 | char* tex_vertex_str = nullptr; | |
| 308 |
3/4✓ Branch 1 taken 640346 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2692589 times.
✓ Branch 4 taken 319560 times.
|
3012149 | for(char* ptr = in.field(i); *ptr != '\0'; ptr++) { |
| 309 |
2/2✓ Branch 0 taken 320786 times.
✓ Branch 1 taken 2371803 times.
|
2692589 | if(*ptr == '/') { |
| 310 |
2/4✓ Branch 0 taken 320786 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 320786 times.
✗ Branch 3 not taken.
|
320786 | if(!ignore_tex_coords && |
| 311 | tex_vertex_str == nullptr) { | ||
| 312 | 320786 | tex_vertex_str = ptr+1; | |
| 313 | } | ||
| 314 | 320786 | *ptr = '\0'; | |
| 315 | 320786 | break; | |
| 316 | } | ||
| 317 | } | ||
| 318 | |||
| 319 | // In .obj files, | ||
| 320 | // negative vertex index means | ||
| 321 | // nb_vertices - vertex index | ||
| 322 | GEO::signed_index_t | ||
| 323 |
2/2✓ Branch 1 taken 640345 times.
✓ Branch 2 taken 1 times.
|
640346 | s_vertex_index = in.field_as_int(i); |
| 324 | 640345 | index_t vertex_index = 0; | |
| 325 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 640345 times.
|
640345 | if(s_vertex_index < 0) { |
| 326 | ✗ | vertex_index = index_t( | |
| 327 | ✗ | 1+int(M.vertices.nb()) + s_vertex_index | |
| 328 | ); | ||
| 329 | } else { | ||
| 330 | 640345 | vertex_index = index_t(s_vertex_index); | |
| 331 | } | ||
| 332 | 640345 | if( | |
| 333 |
5/6✓ Branch 0 taken 640345 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 640344 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 640344 times.
|
1280690 | (vertex_index < 1) || |
| 334 | 640345 | (vertex_index > M.vertices.nb()) | |
| 335 | ) { | ||
| 336 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
2 | Logger::err("I/O") |
| 337 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
|
1 | << "Line " << in.line_number() |
| 338 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | << ": facet corner #" << i |
| 339 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | << " references an invalid vertex: " |
| 340 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | << vertex_index |
| 341 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | << std::endl; |
| 342 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | unbind_attributes(); |
| 343 | 1 | return false; | |
| 344 | } | ||
| 345 |
1/2✓ Branch 1 taken 640344 times.
✗ Branch 2 not taken.
|
640344 | facet_vertices.push_back(vertex_index-1); |
| 346 | |||
| 347 |
2/2✓ Branch 0 taken 320784 times.
✓ Branch 1 taken 319560 times.
|
640344 | if(tex_vertex_str != nullptr && |
| 348 |
1/2✓ Branch 0 taken 320784 times.
✗ Branch 1 not taken.
|
320784 | tex_vertex_str[0] != '\0' && |
| 349 |
1/2✓ Branch 0 taken 320784 times.
✗ Branch 1 not taken.
|
320784 | tex_vertex_str[0] != '/' |
| 350 | ) { | ||
| 351 | 320784 | int s_tex_vertex_index = atoi(tex_vertex_str); | |
| 352 | 320784 | index_t tex_vertex_index = 0; | |
| 353 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 320784 times.
|
320784 | if(s_tex_vertex_index < 0) { |
| 354 | ✗ | tex_vertex_index = index_t( | |
| 355 | ✗ | 1+int(tex_vertices.size()) + | |
| 356 | s_tex_vertex_index | ||
| 357 | ); | ||
| 358 | } else { | ||
| 359 | 320784 | tex_vertex_index = index_t( | |
| 360 | s_tex_vertex_index | ||
| 361 | ); | ||
| 362 | } | ||
| 363 | 320784 | if( | |
| 364 |
3/6✓ Branch 0 taken 320784 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 320784 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 320784 times.
|
641568 | (tex_vertex_index < 1) || |
| 365 | 320784 | (tex_vertex_index > tex_vertices.size()) | |
| 366 | ) { | ||
| 367 | ✗ | Logger::err("I/O") | |
| 368 | ✗ | << "Line " << in.line_number() | |
| 369 | ✗ | << ": facet corner #" << i | |
| 370 | ✗ | << " references an invalid tex vertex: " | |
| 371 | ✗ | << tex_vertex_index | |
| 372 | ✗ | << std::endl; | |
| 373 | ✗ | unbind_attributes(); | |
| 374 | ✗ | return false; | |
| 375 | } | ||
| 376 |
1/2✓ Branch 0 taken 320784 times.
✗ Branch 1 not taken.
|
320784 | if(!ignore_tex_coords) { |
| 377 | 320784 | facet_tex_vertices.push_back( | |
| 378 |
1/2✓ Branch 1 taken 320784 times.
✗ Branch 2 not taken.
|
320784 | tex_vertex_index-1 |
| 379 | ); | ||
| 380 | } | ||
| 381 | } | ||
| 382 | } | ||
| 383 | |||
| 384 | 200602 | if( | |
| 385 |
4/6✓ Branch 1 taken 94128 times.
✓ Branch 2 taken 106474 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 94128 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 200602 times.
|
294730 | facet_tex_vertices.size() != 0 && |
| 386 | 94128 | facet_tex_vertices.size() != facet_vertices.size() | |
| 387 | ) { | ||
| 388 | ✗ | Logger::err("I/O") | |
| 389 | ✗ | << "Line " << in.line_number() << ": " | |
| 390 | ✗ | << "some facet vertices do not have tex vertices" | |
| 391 | ✗ | << std::endl; | |
| 392 | ✗ | unbind_attributes(); | |
| 393 | ✗ | return false; | |
| 394 | } | ||
| 395 | |||
| 396 |
1/2✓ Branch 2 taken 200602 times.
✗ Branch 3 not taken.
|
200602 | index_t f = M.facets.create_polygon( |
| 397 | facet_vertices.size() | ||
| 398 | ); | ||
| 399 |
2/2✓ Branch 1 taken 640343 times.
✓ Branch 2 taken 200602 times.
|
840945 | for(index_t lv=0; lv<facet_vertices.size(); ++lv) { |
| 400 |
2/4✓ Branch 1 taken 640343 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 640343 times.
✗ Branch 5 not taken.
|
640343 | M.facets.set_vertex(f,lv,facet_vertices[lv]); |
| 401 | } | ||
| 402 |
2/2✓ Branch 1 taken 94128 times.
✓ Branch 2 taken 106474 times.
|
200602 | if(facet_tex_vertices.size() != 0) { |
| 403 |
2/2✓ Branch 1 taken 320783 times.
✓ Branch 2 taken 94128 times.
|
414911 | for(index_t lv=0; lv<facet_vertices.size(); ++lv) { |
| 404 |
1/2✓ Branch 1 taken 320783 times.
✗ Branch 2 not taken.
|
320783 | index_t c = M.facets.corners_begin(f) + lv; |
| 405 | const vec2 vt = | ||
| 406 |
2/4✓ Branch 1 taken 320783 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 320783 times.
✗ Branch 5 not taken.
|
320783 | tex_vertices[facet_tex_vertices[lv]]; |
| 407 |
1/2✓ Branch 1 taken 320783 times.
✗ Branch 2 not taken.
|
320783 | tex_coord_[2*c] = vt.x; |
| 408 |
1/2✓ Branch 1 taken 320783 times.
✗ Branch 2 not taken.
|
320783 | tex_coord_[2*c+1] = vt.y; |
| 409 | } | ||
| 410 | } | ||
| 411 | 13235 | } else if( | |
| 412 |
2/2✓ Branch 1 taken 1944 times.
✓ Branch 2 taken 11267 times.
|
26446 | ioflags.has_element(MESH_FACETS) && |
| 413 |
4/4✓ Branch 0 taken 13211 times.
✓ Branch 1 taken 24 times.
✓ Branch 3 taken 1931 times.
✓ Branch 4 taken 11304 times.
|
26446 | facet_region_.is_bound() && |
| 414 |
3/4✓ Branch 1 taken 1944 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1931 times.
✓ Branch 4 taken 13 times.
|
1944 | in.field_matches(0, "#") |
| 415 | ) { | ||
| 416 | 1931 | if( | |
| 417 | 1931 | in.nb_fields() >= 5 && | |
| 418 |
5/8✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1918 times.
✓ Branch 3 taken 13 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 13 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1931 times.
|
1931 | in.field_matches(1, "attribute") && |
| 419 | ✗ | in.field_matches(3, "facet") | |
| 420 | ) { | ||
| 421 | ✗ | if( | |
| 422 | ✗ | first_facet_attribute && | |
| 423 | ✗ | in.field_matches(2, "chart") && | |
| 424 | ✗ | in.field_matches(4, "integer") | |
| 425 | ) { | ||
| 426 | ✗ | read_facet_regions = true; | |
| 427 | } else { | ||
| 428 | ✗ | first_facet_attribute = false; | |
| 429 | } | ||
| 430 | 1931 | } else if( | |
| 431 | ✗ | read_facet_regions && | |
| 432 | ✗ | in.nb_fields() >= 5 && | |
| 433 |
2/8✗ Branch 0 not taken.
✓ Branch 1 taken 1931 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 1931 times.
|
1931 | in.field_matches(1, "attrs") && |
| 434 | ✗ | in.field_matches(2, "f") | |
| 435 | ) { | ||
| 436 | ✗ | index_t facet_index = in.field_as_uint(3); | |
| 437 | ✗ | signed_index_t facet_region = in.field_as_int(4); | |
| 438 | ✗ | if( | |
| 439 | ✗ | (facet_index < 1) || | |
| 440 | ✗ | (facet_index > M.facets.nb()) | |
| 441 | ) { | ||
| 442 | ✗ | Logger::err("I/O") | |
| 443 | ✗ | << "Line " << in.line_number() | |
| 444 | << ": facet attributes " | ||
| 445 | ✗ | << "reference an invalid facet: " | |
| 446 | ✗ | << facet_index | |
| 447 | ✗ | << std::endl; | |
| 448 | ✗ | unbind_attributes(); | |
| 449 | ✗ | return false; | |
| 450 | } | ||
| 451 | |||
| 452 | ✗ | facet_region_[facet_index - 1] = | |
| 453 | ✗ | index_t(facet_region); | |
| 454 | } | ||
| 455 | } | ||
| 456 | } | ||
| 457 | } | ||
| 458 |
1/2✓ Branch 1 taken 164 times.
✗ Branch 2 not taken.
|
164 | unbind_attributes(); |
| 459 | 164 | return true; | |
| 460 | 178 | } | |
| 461 | |||
| 462 | 59 | bool save( | |
| 463 | const Mesh& M, const std::string& filename, | ||
| 464 | const MeshIOFlags& ioflags | ||
| 465 | ) override { | ||
| 466 | |||
| 467 | 59 | std::string mtl_filename; | |
| 468 | 59 | std::string mtl_filename_fullpath; | |
| 469 | |||
| 470 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 59 times.
|
59 | if(ioflags.get_texture_filename().length() != 0) { |
| 471 | mtl_filename = | ||
| 472 | ✗ | FileSystem::base_name(filename) + ".mtl"; | |
| 473 | mtl_filename_fullpath = | ||
| 474 | ✗ | FileSystem::dir_name(filename) + "/" + | |
| 475 | ✗ | mtl_filename; | |
| 476 | ✗ | std::ofstream mtl_out(mtl_filename_fullpath.c_str()); | |
| 477 | ✗ | if(!mtl_out) { | |
| 478 | ✗ | Logger::err("I/O") << "Could not create mtl file " | |
| 479 | ✗ | << mtl_filename_fullpath | |
| 480 | ✗ | << std::endl; | |
| 481 | } else { | ||
| 482 | ✗ | Logger::out("I/O") << "Saving file " | |
| 483 | ✗ | << mtl_filename_fullpath | |
| 484 | ✗ | << std::endl; | |
| 485 | ✗ | mtl_out << "newmtl Material_0" << std::endl; | |
| 486 | mtl_out << "map_Kd " | ||
| 487 | ✗ | << FileSystem::base_name( | |
| 488 | ioflags.get_texture_filename() | ||
| 489 | ) | ||
| 490 | << "." | ||
| 491 | ✗ | << FileSystem::extension( | |
| 492 | ioflags.get_texture_filename() | ||
| 493 | ✗ | ) | |
| 494 | ✗ | << std::endl; | |
| 495 | } | ||
| 496 | ✗ | } | |
| 497 | |||
| 498 |
2/8✓ Branch 1 taken 59 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 59 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
|
59 | geo_assert(M.vertices.dimension() >= dimension_); |
| 499 |
1/2✓ Branch 2 taken 59 times.
✗ Branch 3 not taken.
|
59 | std::ofstream out(filename.c_str()); |
| 500 |
2/4✓ Branch 1 taken 59 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 59 times.
|
59 | if(!out) { |
| 501 | ✗ | Logger::err("I/O") | |
| 502 | << "Could not create file \'" | ||
| 503 | ✗ | << filename << "\'" << std::endl; | |
| 504 | ✗ | return false; | |
| 505 | } | ||
| 506 | |||
| 507 |
1/2✓ Branch 1 taken 59 times.
✗ Branch 2 not taken.
|
59 | bind_attributes(M, ioflags, false); |
| 508 | |||
| 509 | 59 | std::vector<std::string> args; | |
| 510 |
1/2✓ Branch 1 taken 59 times.
✗ Branch 2 not taken.
|
59 | CmdLine::get_args(args); |
| 511 |
2/2✓ Branch 1 taken 2654 times.
✓ Branch 2 taken 59 times.
|
2713 | for(index_t i = 0; i < args.size(); ++i) { |
| 512 |
3/6✓ Branch 1 taken 2654 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 2654 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 2654 times.
✗ Branch 9 not taken.
|
2654 | out << "# vorpaline " << args[i] << std::endl; |
| 513 | } | ||
| 514 | |||
| 515 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 59 times.
|
59 | if(mtl_filename.length() != 0) { |
| 516 | ✗ | out << "mtllib " << mtl_filename << std::endl; | |
| 517 | } | ||
| 518 | |||
| 519 |
1/2✓ Branch 1 taken 59 times.
✗ Branch 2 not taken.
|
59 | vector<double> P(dimension_); |
| 520 |
2/2✓ Branch 1 taken 304048 times.
✓ Branch 2 taken 59 times.
|
304107 | for(index_t v = 0; v < M.vertices.nb(); ++v) { |
| 521 |
1/2✓ Branch 2 taken 304048 times.
✗ Branch 3 not taken.
|
304048 | get_mesh_point(M, v, P.data(), dimension_); |
| 522 |
1/2✓ Branch 1 taken 304048 times.
✗ Branch 2 not taken.
|
304048 | out << "v "; |
| 523 |
2/2✓ Branch 0 taken 912144 times.
✓ Branch 1 taken 304048 times.
|
1216192 | for(index_t c = 0; c < dimension_; ++c) { |
| 524 |
3/6✓ Branch 1 taken 912144 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 912144 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 912144 times.
✗ Branch 8 not taken.
|
912144 | out << P[c] << ' '; |
| 525 | } | ||
| 526 |
1/2✓ Branch 1 taken 304048 times.
✗ Branch 2 not taken.
|
304048 | out << std::endl; |
| 527 | } | ||
| 528 | |||
| 529 | // If mesh has facet corner tex coords, then "compress" tex coords | ||
| 530 | // by generating a single "texture vertex" (vt) for each group of | ||
| 531 | // corners with the same texture coordinates (makes the .obj file | ||
| 532 | // smaller). | ||
| 533 | 59 | vector<index_t> vt_old2new; | |
| 534 | 59 | vector<index_t> vt_index; | |
| 535 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 58 times.
|
59 | if(tex_coord_.is_bound()) { |
| 536 | 1 | index_t nb_vt = Geom::colocate_by_lexico_sort( | |
| 537 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | &tex_coord_[0], 2, M.facet_corners.nb(), vt_old2new, 2 |
| 538 | ); | ||
| 539 |
1/2✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | vt_index.assign(M.facet_corners.nb(), NO_INDEX); |
| 540 | 1 | index_t cur_vt=0; | |
| 541 |
2/2✓ Branch 5 taken 60 times.
✓ Branch 6 taken 1 times.
|
61 | for(index_t c: M.facet_corners) { |
| 542 |
3/4✓ Branch 1 taken 60 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 59 times.
|
60 | if(vt_old2new[c] == c) { |
| 543 |
4/8✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
|
1 | out << "vt " << tex_coord_[2*c] << " " |
| 544 |
3/6✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
|
1 | << tex_coord_[2*c+1] << std::endl; |
| 545 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | vt_index[c] = cur_vt; |
| 546 | 1 | ++cur_vt; | |
| 547 | } | ||
| 548 | } | ||
| 549 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
1 | geo_assert(cur_vt == nb_vt); |
| 550 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 58 times.
|
58 | } else if(vertex_tex_coord_.is_bound()) { |
| 551 | ✗ | for(index_t v: M.vertices) { | |
| 552 | ✗ | out << "vt " << vertex_tex_coord_[2*v] << " " | |
| 553 | ✗ | << vertex_tex_coord_[2*v+1] << std::endl; | |
| 554 | } | ||
| 555 | } | ||
| 556 | |||
| 557 |
2/4✓ Branch 1 taken 59 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 59 times.
✗ Branch 5 not taken.
|
59 | out << "usemtl Material_0" << std::endl; |
| 558 |
1/2✓ Branch 1 taken 59 times.
✗ Branch 2 not taken.
|
59 | if(ioflags.has_element(MESH_FACETS)) { |
| 559 |
2/2✓ Branch 5 taken 293342 times.
✓ Branch 6 taken 59 times.
|
293401 | for(index_t f: M.facets) { |
| 560 |
1/2✓ Branch 1 taken 293342 times.
✗ Branch 2 not taken.
|
293342 | out << "f "; |
| 561 |
1/2✓ Branch 1 taken 293342 times.
✗ Branch 2 not taken.
|
1477425 | for(index_t c = M.facets.corners_begin(f); |
| 562 |
3/4✓ Branch 1 taken 1477425 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1184083 times.
✓ Branch 4 taken 293342 times.
|
1477425 | c < M.facets.corners_end(f); ++c |
| 563 | ) { | ||
| 564 |
2/4✓ Branch 1 taken 1184083 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1184083 times.
✗ Branch 5 not taken.
|
1184083 | out << M.facet_corners.vertex(c) + 1; |
| 565 |
2/2✓ Branch 1 taken 60 times.
✓ Branch 2 taken 1184023 times.
|
1184083 | if(tex_coord_.is_bound()) { |
| 566 |
4/8✓ Branch 1 taken 60 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 60 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 60 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 60 times.
✗ Branch 11 not taken.
|
60 | out << "/" << vt_index[ vt_old2new[c] ] + 1; |
| 567 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1184023 times.
|
1184023 | } else if(vertex_tex_coord_.is_bound()) { |
| 568 | ✗ | out << "/" << M.facet_corners.vertex(c) + 1; | |
| 569 | } | ||
| 570 |
1/2✓ Branch 1 taken 1184083 times.
✗ Branch 2 not taken.
|
1184083 | out << " "; |
| 571 | } | ||
| 572 |
1/2✓ Branch 1 taken 293342 times.
✗ Branch 2 not taken.
|
293342 | out << std::endl; |
| 573 | } | ||
| 574 |
2/2✓ Branch 1 taken 36 times.
✓ Branch 2 taken 23 times.
|
59 | if(facet_region_.is_bound()) { |
| 575 |
2/4✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 36 times.
✗ Branch 5 not taken.
|
36 | out << "# attribute chart facet integer" << std::endl; |
| 576 |
2/2✓ Branch 5 taken 210409 times.
✓ Branch 6 taken 36 times.
|
210445 | for(index_t f: M.facets) { |
| 577 |
1/2✓ Branch 1 taken 210409 times.
✗ Branch 2 not taken.
|
210409 | out << "# attrs f " |
| 578 |
2/4✓ Branch 1 taken 210409 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 210409 times.
✗ Branch 5 not taken.
|
210409 | << f + 1 << " " |
| 579 |
3/6✓ Branch 1 taken 210409 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 210409 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 210409 times.
✗ Branch 8 not taken.
|
210409 | << facet_region_[f] << std::endl; |
| 580 | } | ||
| 581 | } | ||
| 582 | } | ||
| 583 | |||
| 584 |
1/2✓ Branch 1 taken 59 times.
✗ Branch 2 not taken.
|
59 | if(ioflags.has_element(MESH_EDGES)) { |
| 585 |
1/2✗ Branch 5 not taken.
✓ Branch 6 taken 59 times.
|
59 | for(index_t e: M.edges) { |
| 586 | ✗ | out << "l " | |
| 587 | ✗ | << M.edges.vertex(e,0)+1 << " " | |
| 588 | ✗ | << M.edges.vertex(e,1)+1 << std::endl; | |
| 589 | } | ||
| 590 | } | ||
| 591 | |||
| 592 |
1/2✓ Branch 1 taken 59 times.
✗ Branch 2 not taken.
|
59 | unbind_attributes(); |
| 593 | |||
| 594 | 59 | return true; | |
| 595 | 59 | } | |
| 596 | |||
| 597 | protected: | ||
| 598 | 908 | ~OBJIOHandler() override { | |
| 599 | 908 | } | |
| 600 | |||
| 601 | 226 | void bind_attributes( | |
| 602 | const Mesh& M, const MeshIOFlags& flags, bool create | ||
| 603 | ) override { | ||
| 604 | 226 | MeshIOHandler::bind_attributes(M, flags, create); | |
| 605 | |||
| 606 |
1/2✓ Branch 2 taken 226 times.
✗ Branch 3 not taken.
|
452 | tex_coord_.bind_if_is_defined( |
| 607 |
1/2✓ Branch 1 taken 226 times.
✗ Branch 2 not taken.
|
452 | M.facet_corners.attributes(), "tex_coord" |
| 608 | ); | ||
| 609 |
4/6✓ Branch 1 taken 1 times.
✓ Branch 2 taken 225 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 226 times.
|
226 | if(tex_coord_.is_bound() && tex_coord_.dimension() != 2) { |
| 610 | ✗ | tex_coord_.unbind(); | |
| 611 | } | ||
| 612 | |||
| 613 |
1/2✓ Branch 2 taken 226 times.
✗ Branch 3 not taken.
|
452 | vertex_tex_coord_.bind_if_is_defined( |
| 614 |
1/2✓ Branch 1 taken 226 times.
✗ Branch 2 not taken.
|
452 | M.vertices.attributes(), "tex_coord" |
| 615 | ); | ||
| 616 | 226 | if( | |
| 617 |
2/6✗ Branch 1 not taken.
✓ Branch 2 taken 226 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 226 times.
|
226 | vertex_tex_coord_.is_bound() && |
| 618 | ✗ | vertex_tex_coord_.dimension() != 2 | |
| 619 | ) { | ||
| 620 | ✗ | vertex_tex_coord_.unbind(); | |
| 621 | } | ||
| 622 | |||
| 623 | 226 | } | |
| 624 | |||
| 625 | 224 | void unbind_attributes() override { | |
| 626 |
2/2✓ Branch 1 taken 115 times.
✓ Branch 2 taken 109 times.
|
224 | if(tex_coord_.is_bound()) { |
| 627 | 115 | tex_coord_.unbind(); | |
| 628 | } | ||
| 629 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 224 times.
|
224 | if(vertex_tex_coord_.is_bound()) { |
| 630 | ✗ | vertex_tex_coord_.unbind(); | |
| 631 | } | ||
| 632 | 224 | MeshIOHandler::unbind_attributes(); | |
| 633 | 224 | } | |
| 634 | |||
| 635 | private: | ||
| 636 | coord_index_t dimension_; | ||
| 637 | Attribute<double> tex_coord_; | ||
| 638 | Attribute<double> vertex_tex_coord_; | ||
| 639 | }; | ||
| 640 | |||
| 641 | |||
| 642 | /************************************************************************/ | ||
| 643 | |||
| 644 | /** | ||
| 645 | * \brief IO handler for the OBJ6 file format | ||
| 646 | * \see OBJIOHandler | ||
| 647 | */ | ||
| 648 | class GEOGRAM_API OBJ6IOHandler : public OBJIOHandler { | ||
| 649 | public: | ||
| 650 | ✗ | OBJ6IOHandler() : | |
| 651 | ✗ | OBJIOHandler(6) { | |
| 652 | ✗ | } | |
| 653 | }; | ||
| 654 | |||
| 655 | /************************************************************************/ | ||
| 656 | |||
| 657 | |||
| 658 | /** | ||
| 659 | * \brief IO handler for LM5/LM6/Gamma mesh file format | ||
| 660 | * \see http://www-roc.inria.fr/gamma/gamma/Membres/CIPD/Loic.Marechal/Research/LM5.html | ||
| 661 | */ | ||
| 662 | class GEOGRAM_API LMIOHandler : public MeshIOHandler { | ||
| 663 | public: | ||
| 664 | |||
| 665 |
2/4✓ Branch 2 taken 22748 times.
✓ Branch 3 taken 94 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
22842 | LMIOHandler() { |
| 666 | |||
| 667 |
1/2✓ Branch 1 taken 94 times.
✗ Branch 2 not taken.
|
94 | geo_cite("WEB:libMeshb"); |
| 668 | |||
| 669 |
1/2✓ Branch 1 taken 94 times.
✗ Branch 2 not taken.
|
94 | keyword2name_[GmfTriangles] = "triangle"; |
| 670 |
1/2✓ Branch 1 taken 94 times.
✗ Branch 2 not taken.
|
94 | keyword2name_[GmfQuadrilaterals] = "quad"; |
| 671 |
1/2✓ Branch 1 taken 94 times.
✗ Branch 2 not taken.
|
94 | keyword2name_[GmfTetrahedra] = "tet"; |
| 672 |
1/2✓ Branch 1 taken 94 times.
✗ Branch 2 not taken.
|
94 | keyword2name_[GmfHexahedra] = "hex"; |
| 673 |
1/2✓ Branch 1 taken 94 times.
✗ Branch 2 not taken.
|
94 | keyword2name_[GmfPrisms] = "prism"; |
| 674 |
1/2✓ Branch 1 taken 94 times.
✗ Branch 2 not taken.
|
94 | keyword2name_[GmfPyramids] = "pyramid"; |
| 675 |
1/2✓ Branch 1 taken 94 times.
✗ Branch 2 not taken.
|
94 | keyword2name_[GmfEdges] = "edge"; |
| 676 | 94 | keyword2nbv_[GmfTriangles] = 3; | |
| 677 | 94 | keyword2nbv_[GmfQuadrilaterals] = 4; | |
| 678 | 94 | keyword2nbv_[GmfTetrahedra] = 4; | |
| 679 | 94 | keyword2nbv_[GmfHexahedra] = 8; | |
| 680 | 94 | keyword2nbv_[GmfPrisms] = 6; | |
| 681 | 94 | keyword2nbv_[GmfPyramids] = 5; | |
| 682 | 94 | keyword2nbv_[GmfEdges] = 2; | |
| 683 |
0/2✗ Branch 0 not taken.
✗ Branch 1 not taken.
|
94 | } |
| 684 | |||
| 685 | 39 | bool load( | |
| 686 | const std::string& filename, Mesh& M, | ||
| 687 | const MeshIOFlags& ioflags | ||
| 688 | ) override { | ||
| 689 | |||
| 690 | int ver, dim; | ||
| 691 |
1/2✓ Branch 2 taken 39 times.
✗ Branch 3 not taken.
|
39 | int64_t mesh_file_handle = GmfOpenMesh( |
| 692 | const_cast<char*>(filename.c_str()), GmfRead, &ver, &dim | ||
| 693 | ); | ||
| 694 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 38 times.
|
39 | if(!mesh_file_handle) { |
| 695 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
2 | Logger::err("I/O") << "Could not open file: " |
| 696 |
3/6✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
|
1 | << filename << std::endl; |
| 697 | 1 | return false; | |
| 698 | } | ||
| 699 | |||
| 700 | // indices coords | ||
| 701 | // ver=1 int32 float32 | ||
| 702 | // ver=2 int32 float64 | ||
| 703 | // ver=3 int32 float64 | ||
| 704 | // ver=4 int64 float64 | ||
| 705 | // TODO: handle ver=4 in GARGANTUA mode | ||
| 706 |
3/6✓ Branch 0 taken 12 times.
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
38 | if(ver != 1 && ver != 2 && ver != 3) { |
| 707 | ✗ | Logger::err("I/O") << "Invalid version: " << ver << std::endl; | |
| 708 | ✗ | GmfCloseMesh(mesh_file_handle); | |
| 709 | ✗ | return false; | |
| 710 | } | ||
| 711 | |||
| 712 | 38 | bool use_doubles = (ver != 1); | |
| 713 | |||
| 714 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
38 | if(dim != 3 && dim != 2) { |
| 715 | ✗ | Logger::err("I/O") << "Invalid dimension: " << dim << std::endl; | |
| 716 | ✗ | GmfCloseMesh(mesh_file_handle); | |
| 717 | ✗ | return false; | |
| 718 | } | ||
| 719 | |||
| 720 |
1/2✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
|
38 | bind_attributes(M, ioflags, true); |
| 721 | |||
| 722 | index_t nb_vertices = | ||
| 723 |
1/2✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
|
38 | index_t(GmfStatKwd(mesh_file_handle, GmfVertices)); |
| 724 | |||
| 725 | index_t nb_edges = | ||
| 726 |
1/2✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
|
38 | index_t(GmfStatKwd(mesh_file_handle, GmfEdges)); |
| 727 | |||
| 728 | index_t nb_tris = | ||
| 729 |
1/2✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
|
38 | index_t(GmfStatKwd(mesh_file_handle, GmfTriangles)); |
| 730 | index_t nb_quads = | ||
| 731 |
1/2✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
|
38 | index_t(GmfStatKwd(mesh_file_handle, GmfQuadrilaterals)); |
| 732 | |||
| 733 | index_t nb_tets = | ||
| 734 |
1/2✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
|
38 | index_t(GmfStatKwd(mesh_file_handle, GmfTetrahedra)); |
| 735 | index_t nb_hexes = | ||
| 736 |
1/2✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
|
38 | index_t(GmfStatKwd(mesh_file_handle, GmfHexahedra)); |
| 737 | index_t nb_prisms = | ||
| 738 |
1/2✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
|
38 | index_t(GmfStatKwd(mesh_file_handle, GmfPrisms)); |
| 739 | index_t nb_pyramids = | ||
| 740 |
1/2✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
|
38 | index_t(GmfStatKwd(mesh_file_handle, GmfPyramids)); |
| 741 | |||
| 742 | // Read vertices | ||
| 743 |
2/4✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 38 times.
|
38 | if(!goto_elements(mesh_file_handle, GmfVertices)) { |
| 744 | ✗ | return false; | |
| 745 | } | ||
| 746 |
1/2✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
|
38 | M.vertices.create_vertices(nb_vertices); |
| 747 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 26 times.
|
38 | if(use_doubles) { |
| 748 |
2/2✓ Branch 0 taken 13492 times.
✓ Branch 1 taken 12 times.
|
13504 | for(index_t v = 0; v < index_t(nb_vertices); ++v) { |
| 749 | double xyz[3]; | ||
| 750 | 13492 | int ref = 0; | |
| 751 | 13492 | xyz[2] = 0.0; | |
| 752 |
2/8✗ Branch 0 not taken.
✓ Branch 1 taken 13492 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 13492 times.
|
13492 | if(dim == 2 && !GmfGetLin( |
| 753 | mesh_file_handle, GmfVertices, | ||
| 754 | &xyz[0], &xyz[1], &ref | ||
| 755 | )) { | ||
| 756 | ✗ | Logger::err("I/O") << "Failed to read vertex #" << v | |
| 757 | ✗ | << std::endl; | |
| 758 | ✗ | GmfCloseMesh(mesh_file_handle); | |
| 759 | ✗ | unbind_attributes(); | |
| 760 | ✗ | return false; | |
| 761 | } | ||
| 762 |
4/8✓ Branch 0 taken 13492 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 13492 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 13492 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 13492 times.
|
13492 | if(dim == 3 && !GmfGetLin( |
| 763 | mesh_file_handle, GmfVertices, | ||
| 764 | &xyz[0], &xyz[1], &xyz[2], &ref | ||
| 765 | )) { | ||
| 766 | ✗ | Logger::err("I/O") << "Failed to read vertex #" << v | |
| 767 | ✗ | << std::endl; | |
| 768 | ✗ | GmfCloseMesh(mesh_file_handle); | |
| 769 | ✗ | unbind_attributes(); | |
| 770 | ✗ | return false; | |
| 771 | } | ||
| 772 |
1/2✓ Branch 1 taken 13492 times.
✗ Branch 2 not taken.
|
13492 | set_mesh_point(M,v,xyz,3); |
| 773 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 13492 times.
|
13492 | if(vertex_region_.is_bound()) { |
| 774 | ✗ | vertex_region_[v] = index_t(ref); | |
| 775 | } | ||
| 776 | } | ||
| 777 | } else { | ||
| 778 |
2/2✓ Branch 0 taken 56101 times.
✓ Branch 1 taken 26 times.
|
56127 | for(index_t v = 0; v < index_t(nb_vertices); ++v) { |
| 779 | 56101 | float x=0.0f,y=0.0f,z=0.0f; | |
| 780 | double xyz[3]; | ||
| 781 | 56101 | int ref = 0; | |
| 782 |
2/8✗ Branch 0 not taken.
✓ Branch 1 taken 56101 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 56101 times.
|
56101 | if(dim == 2 && !GmfGetLin( |
| 783 | mesh_file_handle, GmfVertices, &x, &y, &ref) | ||
| 784 | ) { | ||
| 785 | ✗ | Logger::err("I/O") << "Failed to read vertex #" << v | |
| 786 | ✗ | << std::endl; | |
| 787 | ✗ | GmfCloseMesh(mesh_file_handle); | |
| 788 | ✗ | return false; | |
| 789 | } | ||
| 790 |
4/8✓ Branch 0 taken 56101 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 56101 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 56101 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 56101 times.
|
56101 | if(dim == 3 && !GmfGetLin( |
| 791 | mesh_file_handle, GmfVertices, &x, &y, &z, &ref) | ||
| 792 | ) { | ||
| 793 | ✗ | Logger::err("I/O") << "Failed to read vertex #" << v | |
| 794 | ✗ | << std::endl; | |
| 795 | ✗ | GmfCloseMesh(mesh_file_handle); | |
| 796 | ✗ | return false; | |
| 797 | } | ||
| 798 | 56101 | xyz[0] = double(x); | |
| 799 | 56101 | xyz[1] = double(y); | |
| 800 | 56101 | xyz[2] = double(z); | |
| 801 |
1/2✓ Branch 1 taken 56101 times.
✗ Branch 2 not taken.
|
56101 | set_mesh_point(M,v,xyz,3); |
| 802 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 56101 times.
|
56101 | if(vertex_region_.is_bound()) { |
| 803 | ✗ | vertex_region_[v] = index_t(ref); | |
| 804 | } | ||
| 805 | } | ||
| 806 | } | ||
| 807 | |||
| 808 |
1/2✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
|
38 | if(ioflags.has_element(MESH_EDGES)) { |
| 809 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 38 times.
|
38 | if(nb_edges > 0) { |
| 810 | ✗ | if(!goto_elements(mesh_file_handle, GmfEdges)) { | |
| 811 | ✗ | return false; | |
| 812 | } | ||
| 813 | ✗ | index_t first_edge = M.edges.create_edges(nb_edges); | |
| 814 | int v[8]; | ||
| 815 | int ref; | ||
| 816 | ✗ | for(index_t e=0; e<nb_edges; ++e) { | |
| 817 | ✗ | if(!read_element( | |
| 818 | mesh_file_handle, GmfEdges, v, ref, M, e | ||
| 819 | )) { | ||
| 820 | ✗ | return false; | |
| 821 | } | ||
| 822 | ✗ | for(index_t lv=0; lv<2; ++lv) { | |
| 823 | ✗ | M.edges.set_vertex( | |
| 824 | ✗ | first_edge+e, lv, index_t(v[lv]-1) | |
| 825 | ); | ||
| 826 | } | ||
| 827 | ✗ | if(edge_region_.is_bound()) { | |
| 828 | ✗ | edge_region_[first_edge+e] = index_t(ref); | |
| 829 | } | ||
| 830 | } | ||
| 831 | } | ||
| 832 | } | ||
| 833 | |||
| 834 |
1/2✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
|
38 | if(ioflags.has_element(MESH_FACETS)) { |
| 835 | // Read triangles | ||
| 836 |
2/2✓ Branch 0 taken 34 times.
✓ Branch 1 taken 4 times.
|
38 | if(nb_tris > 0) { |
| 837 |
2/4✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 34 times.
|
34 | if(!goto_elements(mesh_file_handle, GmfTriangles)) { |
| 838 | 2 | return false; | |
| 839 | } | ||
| 840 |
1/2✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
|
34 | index_t first_tri = M.facets.create_triangles(nb_tris); |
| 841 | int v[8]; | ||
| 842 | int ref; | ||
| 843 |
2/2✓ Branch 0 taken 126255 times.
✓ Branch 1 taken 32 times.
|
126287 | for(index_t t=0; t<nb_tris; ++t) { |
| 844 |
3/4✓ Branch 1 taken 126255 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 126253 times.
|
126255 | if(!read_element( |
| 845 | mesh_file_handle, GmfTriangles, v, ref, M, t | ||
| 846 | )) { | ||
| 847 | 2 | return false; | |
| 848 | } | ||
| 849 |
2/2✓ Branch 0 taken 378759 times.
✓ Branch 1 taken 126253 times.
|
505012 | for(index_t lv=0; lv<3; ++lv) { |
| 850 | 378759 | M.facets.set_vertex( | |
| 851 |
1/2✓ Branch 1 taken 378759 times.
✗ Branch 2 not taken.
|
378759 | first_tri+t, lv, index_t(v[lv]-1) |
| 852 | ); | ||
| 853 | } | ||
| 854 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 126253 times.
|
126253 | if(facet_region_.is_bound()) { |
| 855 | ✗ | facet_region_[first_tri+t] = index_t(ref); | |
| 856 | } | ||
| 857 | } | ||
| 858 | } | ||
| 859 | |||
| 860 | // Read quads | ||
| 861 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 32 times.
|
36 | if(nb_quads > 0) { |
| 862 |
2/4✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
|
4 | if(!goto_elements(mesh_file_handle, GmfQuadrilaterals)) { |
| 863 | ✗ | return false; | |
| 864 | } | ||
| 865 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | index_t first_quad = M.facets.create_quads(nb_quads); |
| 866 | int v[8]; | ||
| 867 | int ref; | ||
| 868 |
2/2✓ Branch 0 taken 40 times.
✓ Branch 1 taken 4 times.
|
44 | for(index_t q=0; q<nb_quads; ++q) { |
| 869 |
2/4✓ Branch 1 taken 40 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 40 times.
|
40 | if(!read_element( |
| 870 | mesh_file_handle, GmfQuadrilaterals, | ||
| 871 | v, ref, M, q | ||
| 872 | )) { | ||
| 873 | ✗ | return false; | |
| 874 | } | ||
| 875 |
2/2✓ Branch 0 taken 160 times.
✓ Branch 1 taken 40 times.
|
200 | for(index_t lv=0; lv<4; ++lv) { |
| 876 | 160 | M.facets.set_vertex( | |
| 877 |
1/2✓ Branch 1 taken 160 times.
✗ Branch 2 not taken.
|
160 | first_quad+q, lv, index_t(v[lv]-1) |
| 878 | ); | ||
| 879 | } | ||
| 880 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 40 times.
|
40 | if(facet_region_.is_bound()) { |
| 881 | ✗ | facet_region_[first_quad+q] = index_t(ref); | |
| 882 | } | ||
| 883 | } | ||
| 884 | } | ||
| 885 | } | ||
| 886 | |||
| 887 |
1/2✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
|
36 | if(ioflags.has_element(MESH_CELLS)) { |
| 888 | |||
| 889 | // Read tets | ||
| 890 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 35 times.
|
36 | if(nb_tets > 0) { |
| 891 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
|
1 | if(!goto_elements(mesh_file_handle, GmfTetrahedra)) { |
| 892 | ✗ | return false; | |
| 893 | } | ||
| 894 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | index_t first_tet = M.cells.create_tets(nb_tets); |
| 895 | int v[8]; | ||
| 896 | int ref; | ||
| 897 |
2/2✓ Branch 0 taken 10535 times.
✓ Branch 1 taken 1 times.
|
10536 | for(index_t t=0; t<nb_tets; ++t) { |
| 898 |
2/4✓ Branch 1 taken 10535 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 10535 times.
|
10535 | if(!read_element( |
| 899 | mesh_file_handle, GmfTetrahedra, v, ref, M, t | ||
| 900 | )) { | ||
| 901 | ✗ | return false; | |
| 902 | } | ||
| 903 |
2/2✓ Branch 0 taken 42140 times.
✓ Branch 1 taken 10535 times.
|
52675 | for(index_t lv=0; lv<4; ++lv) { |
| 904 | 42140 | M.cells.set_vertex( | |
| 905 |
1/2✓ Branch 1 taken 42140 times.
✗ Branch 2 not taken.
|
42140 | first_tet+t, lv, index_t(v[lv]-1) |
| 906 | ); | ||
| 907 | } | ||
| 908 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 10535 times.
|
10535 | if(cell_region_.is_bound()) { |
| 909 | ✗ | cell_region_[first_tet+t] = index_t(ref); | |
| 910 | } | ||
| 911 | } | ||
| 912 | } | ||
| 913 | |||
| 914 | // Read hexes | ||
| 915 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 36 times.
|
36 | if(nb_hexes > 0) { |
| 916 | ✗ | if(!goto_elements(mesh_file_handle, GmfHexahedra)) { | |
| 917 | ✗ | return false; | |
| 918 | } | ||
| 919 | ✗ | index_t first_hex = M.cells.create_hexes(nb_hexes); | |
| 920 | |||
| 921 | int v[8]; | ||
| 922 | int ref; | ||
| 923 | ✗ | for(index_t h=0; h<nb_hexes; ++h) { | |
| 924 | ✗ | if(!read_element( | |
| 925 | mesh_file_handle, GmfHexahedra, v, ref, M, h | ||
| 926 | )) { | ||
| 927 | ✗ | return false; | |
| 928 | } | ||
| 929 | |||
| 930 | // Swapping vertices 1<->0 and 4<->5 to | ||
| 931 | // account for differences in the indexing | ||
| 932 | // convetions in .mesh/.meshb files w.r.t. | ||
| 933 | // geogram internal conventions. | ||
| 934 | ✗ | std::swap(v[0], v[1]); | |
| 935 | ✗ | std::swap(v[4], v[5]); | |
| 936 | |||
| 937 | ✗ | for(index_t lv=0; lv<8; ++lv) { | |
| 938 | ✗ | M.cells.set_vertex( | |
| 939 | ✗ | first_hex+h, lv, index_t(v[lv]-1) | |
| 940 | ); | ||
| 941 | } | ||
| 942 | ✗ | if(cell_region_.is_bound()) { | |
| 943 | ✗ | cell_region_[first_hex+h] = index_t(ref); | |
| 944 | } | ||
| 945 | } | ||
| 946 | } | ||
| 947 | |||
| 948 | // Read prisms | ||
| 949 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 36 times.
|
36 | if(nb_prisms > 0) { |
| 950 | ✗ | if(!goto_elements(mesh_file_handle, GmfPrisms)) { | |
| 951 | ✗ | return false; | |
| 952 | } | ||
| 953 | ✗ | index_t first_prism = M.cells.create_prisms(nb_prisms); | |
| 954 | int v[8]; | ||
| 955 | int ref; | ||
| 956 | ✗ | for(index_t p=0; p<nb_prisms; ++p) { | |
| 957 | ✗ | if(!read_element( | |
| 958 | mesh_file_handle, GmfPrisms, v, ref, M, p | ||
| 959 | )) { | ||
| 960 | ✗ | return false; | |
| 961 | } | ||
| 962 | ✗ | for(index_t lv=0; lv<6; ++lv) { | |
| 963 | ✗ | M.cells.set_vertex( | |
| 964 | ✗ | first_prism+p, lv, index_t(v[lv]-1) | |
| 965 | ); | ||
| 966 | } | ||
| 967 | ✗ | if(cell_region_.is_bound()) { | |
| 968 | ✗ | cell_region_[first_prism+p] = index_t(ref); | |
| 969 | } | ||
| 970 | } | ||
| 971 | } | ||
| 972 | |||
| 973 | // Read pyramids | ||
| 974 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 36 times.
|
36 | if(nb_pyramids > 0) { |
| 975 | ✗ | if(!goto_elements(mesh_file_handle, GmfPyramids)) { | |
| 976 | ✗ | return false; | |
| 977 | } | ||
| 978 | index_t first_pyramid = | ||
| 979 | ✗ | M.cells.create_pyramids(nb_pyramids); | |
| 980 | int v[8]; | ||
| 981 | int ref; | ||
| 982 | ✗ | for(index_t p=0; p<nb_pyramids; ++p) { | |
| 983 | ✗ | if(!read_element( | |
| 984 | mesh_file_handle, GmfPyramids, v, ref, M, p | ||
| 985 | )) { | ||
| 986 | ✗ | return false; | |
| 987 | } | ||
| 988 | ✗ | for(index_t lv=0; lv<5; ++lv) { | |
| 989 | ✗ | M.cells.set_vertex( | |
| 990 | ✗ | first_pyramid+p, lv, index_t(v[lv]-1) | |
| 991 | ); | ||
| 992 | } | ||
| 993 | ✗ | if(cell_region_.is_bound()) { | |
| 994 | ✗ | cell_region_[first_pyramid+p] = index_t(ref); | |
| 995 | } | ||
| 996 | } | ||
| 997 | } | ||
| 998 | } | ||
| 999 | |||
| 1000 |
1/2✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
|
36 | GmfCloseMesh(mesh_file_handle); |
| 1001 |
1/2✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
|
36 | unbind_attributes(); |
| 1002 | 36 | return true; | |
| 1003 | } | ||
| 1004 | |||
| 1005 | 55 | bool save( | |
| 1006 | const Mesh& M, const std::string& filename, | ||
| 1007 | const MeshIOFlags& ioflags | ||
| 1008 | ) override { | ||
| 1009 |
2/4✓ Branch 1 taken 55 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 55 times.
✗ Branch 5 not taken.
|
55 | bool use_doubles = CmdLine::get_arg_bool("sys:use_doubles"); |
| 1010 | |||
| 1011 | // indices coords | ||
| 1012 | // ver=1 int32 float32 | ||
| 1013 | // ver=2 int32 float64 | ||
| 1014 | // ver=3 int32 float64 | ||
| 1015 | // ver=4 int64 float64 | ||
| 1016 | // TODO: handle ver=4 in GARGANTUA mode | ||
| 1017 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
|
55 | int ver = use_doubles ? 2 : 1; |
| 1018 | |||
| 1019 | 55 | int64_t mesh_file_handle = GmfOpenMesh( | |
| 1020 | const_cast<char*>(filename.c_str()), GmfWrite, | ||
| 1021 | ver, 3 | ||
| 1022 | ); | ||
| 1023 | |||
| 1024 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
|
55 | if(mesh_file_handle == 0) { |
| 1025 | ✗ | Logger::err("I/O") | |
| 1026 | ✗ | << "Could not create file \'" << filename << "\'" | |
| 1027 | ✗ | << std::endl; | |
| 1028 | ✗ | return false; | |
| 1029 | } | ||
| 1030 | 55 | bind_attributes(M, ioflags, false); | |
| 1031 | |||
| 1032 | // Save vertices | ||
| 1033 | 55 | GmfSetKwd(mesh_file_handle, GmfVertices, int64_t(M.vertices.nb())); | |
| 1034 |
2/2✓ Branch 1 taken 145157 times.
✓ Branch 2 taken 55 times.
|
145212 | for(index_t v = 0; v < M.vertices.nb(); ++v) { |
| 1035 | double xyz[3]; | ||
| 1036 | index_t ref = | ||
| 1037 |
3/4✓ Branch 1 taken 22680 times.
✓ Branch 2 taken 122477 times.
✓ Branch 4 taken 22680 times.
✗ Branch 5 not taken.
|
145157 | vertex_region_.is_bound() ? vertex_region_[v] : 0; |
| 1038 |
1/2✓ Branch 1 taken 145157 times.
✗ Branch 2 not taken.
|
145157 | get_mesh_point(M, v, xyz, 3); |
| 1039 |
1/2✓ Branch 1 taken 145157 times.
✗ Branch 2 not taken.
|
145157 | GmfSetLin( |
| 1040 | mesh_file_handle, GmfVertices, xyz[0], xyz[1], xyz[2], ref | ||
| 1041 | ); | ||
| 1042 | } | ||
| 1043 | |||
| 1044 |
1/2✓ Branch 1 taken 55 times.
✗ Branch 2 not taken.
|
55 | if(ioflags.has_element(MESH_FACETS)) { |
| 1045 | |||
| 1046 | 55 | index_t nb_tris = 0; | |
| 1047 | 55 | index_t nb_quads = 0; | |
| 1048 | 55 | index_t nb_other = 0; | |
| 1049 | |||
| 1050 |
2/2✓ Branch 1 taken 284899 times.
✓ Branch 2 taken 55 times.
|
284954 | for(index_t f = 0; f < M.facets.nb(); ++f) { |
| 1051 |
1/3✓ Branch 1 taken 284899 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
284899 | switch(M.facets.nb_vertices(f)) { |
| 1052 | 284899 | case 3: | |
| 1053 | 284899 | nb_tris++; | |
| 1054 | 284899 | break; | |
| 1055 | ✗ | case 4: | |
| 1056 | ✗ | nb_quads++; | |
| 1057 | ✗ | break; | |
| 1058 | ✗ | default: | |
| 1059 | ✗ | nb_other++; | |
| 1060 | ✗ | break; | |
| 1061 | } | ||
| 1062 | } | ||
| 1063 | |||
| 1064 |
2/2✓ Branch 0 taken 51 times.
✓ Branch 1 taken 4 times.
|
55 | if(nb_tris > 0) { |
| 1065 | 51 | GmfSetKwd(mesh_file_handle, GmfTriangles, int64_t(nb_tris)); | |
| 1066 |
2/2✓ Branch 1 taken 284899 times.
✓ Branch 2 taken 51 times.
|
284950 | for(index_t f = 0; f < M.facets.nb(); ++f) { |
| 1067 |
1/2✓ Branch 1 taken 284899 times.
✗ Branch 2 not taken.
|
284899 | if(M.facets.nb_vertices(f) == 3) { |
| 1068 | index_t ref = | ||
| 1069 |
2/2✓ Branch 1 taken 45308 times.
✓ Branch 2 taken 239591 times.
|
284899 | facet_region_.is_bound() ? |
| 1070 | 284899 | facet_region_[f] : 0 ; | |
| 1071 | 1139596 | GmfSetLin( | |
| 1072 | mesh_file_handle, GmfTriangles, | ||
| 1073 | 284899 | int(M.facets.vertex(f,0)+1), | |
| 1074 | 284899 | int(M.facets.vertex(f,1)+1), | |
| 1075 | 284899 | int(M.facets.vertex(f,2)+1), | |
| 1076 | int(ref) | ||
| 1077 | ); | ||
| 1078 | } | ||
| 1079 | } | ||
| 1080 | } | ||
| 1081 | |||
| 1082 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
|
55 | if(nb_quads > 0) { |
| 1083 | ✗ | GmfSetKwd( | |
| 1084 | mesh_file_handle, GmfQuadrilaterals, int64_t(nb_quads) | ||
| 1085 | ); | ||
| 1086 | ✗ | for(index_t f = 0; f < M.facets.nb(); ++f) { | |
| 1087 | ✗ | if(M.facets.nb_vertices(f) == 4) { | |
| 1088 | index_t ref = | ||
| 1089 | ✗ | facet_region_.is_bound() ? | |
| 1090 | ✗ | facet_region_[f] : 0 ; | |
| 1091 | ✗ | GmfSetLin( | |
| 1092 | mesh_file_handle, GmfQuadrilaterals, | ||
| 1093 | ✗ | int(M.facets.vertex(f,0)+1), | |
| 1094 | ✗ | int(M.facets.vertex(f,1)+1), | |
| 1095 | ✗ | int(M.facets.vertex(f,2)+1), | |
| 1096 | ✗ | int(M.facets.vertex(f,3)+1), | |
| 1097 | int(ref) | ||
| 1098 | ); | ||
| 1099 | } | ||
| 1100 | } | ||
| 1101 | } | ||
| 1102 | |||
| 1103 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
|
55 | if(nb_other > 0) { |
| 1104 | ✗ | Logger::warn("I/O") | |
| 1105 | ✗ | << "Encountered " << nb_other | |
| 1106 | << " non-tri / non-quad facets" | ||
| 1107 | ✗ | << " (not saved)" | |
| 1108 | ✗ | << std::endl; | |
| 1109 | ✗ | Logger::warn("I/O") | |
| 1110 | ✗ | << "Use another file format (e.g., .obj or .geogram)" | |
| 1111 | ✗ | << std::endl; | |
| 1112 | |||
| 1113 | } | ||
| 1114 | } | ||
| 1115 | |||
| 1116 |
1/2✓ Branch 1 taken 55 times.
✗ Branch 2 not taken.
|
55 | if(ioflags.has_element(MESH_EDGES)) { |
| 1117 | 55 | GmfSetKwd(mesh_file_handle, GmfEdges, int64_t(M.edges.nb())); | |
| 1118 |
2/2✓ Branch 1 taken 164 times.
✓ Branch 2 taken 55 times.
|
219 | for(index_t e=0; e<M.edges.nb(); ++e) { |
| 1119 | 164 | index_t ref = 0; | |
| 1120 | 328 | GmfSetLin( | |
| 1121 | mesh_file_handle, GmfEdges, | ||
| 1122 | 164 | int(M.edges.vertex(e,0) + 1), | |
| 1123 | 164 | int(M.edges.vertex(e,1) + 1), | |
| 1124 | ref | ||
| 1125 | ); | ||
| 1126 | } | ||
| 1127 | } | ||
| 1128 | |||
| 1129 |
1/2✓ Branch 1 taken 55 times.
✗ Branch 2 not taken.
|
55 | if(ioflags.has_element(MESH_CELLS)) { |
| 1130 | 55 | index_t nb_tets=0; | |
| 1131 | 55 | index_t nb_hexes=0; | |
| 1132 | 55 | index_t nb_prisms=0; | |
| 1133 | 55 | index_t nb_pyramids=0; | |
| 1134 |
2/2✓ Branch 1 taken 12093 times.
✓ Branch 2 taken 55 times.
|
12148 | for(index_t c=0; c<M.cells.nb(); ++c) { |
| 1135 |
1/6✓ Branch 1 taken 12093 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
|
12093 | switch(M.cells.type(c)) { |
| 1136 | 12093 | case MESH_TET: | |
| 1137 | 12093 | ++nb_tets; | |
| 1138 | 12093 | break; | |
| 1139 | ✗ | case MESH_HEX: | |
| 1140 | ✗ | ++nb_hexes; | |
| 1141 | ✗ | break; | |
| 1142 | ✗ | case MESH_PRISM: | |
| 1143 | ✗ | ++nb_prisms; | |
| 1144 | ✗ | break; | |
| 1145 | ✗ | case MESH_PYRAMID: | |
| 1146 | ✗ | ++nb_pyramids; | |
| 1147 | ✗ | break; | |
| 1148 | ✗ | case MESH_CONNECTOR: | |
| 1149 | case MESH_NB_CELL_TYPES: | ||
| 1150 | ✗ | break; | |
| 1151 | } | ||
| 1152 | } | ||
| 1153 | |||
| 1154 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 50 times.
|
55 | if(nb_tets > 0) { |
| 1155 | 5 | GmfSetKwd( | |
| 1156 | mesh_file_handle, GmfTetrahedra, int64_t(nb_tets) | ||
| 1157 | ); | ||
| 1158 |
2/2✓ Branch 1 taken 12093 times.
✓ Branch 2 taken 5 times.
|
12098 | for(index_t c=0; c<M.cells.nb(); ++c) { |
| 1159 |
1/2✓ Branch 1 taken 12093 times.
✗ Branch 2 not taken.
|
12093 | if(M.cells.type(c) == MESH_TET) { |
| 1160 | index_t ref = | ||
| 1161 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 12093 times.
|
12093 | cell_region_.is_bound() ? cell_region_[c] : 0; |
| 1162 | 48372 | GmfSetLin( | |
| 1163 | mesh_file_handle, GmfTetrahedra, | ||
| 1164 | 12093 | int(M.cells.vertex(c,0) + 1), | |
| 1165 | 12093 | int(M.cells.vertex(c,1) + 1), | |
| 1166 | 12093 | int(M.cells.vertex(c,2) + 1), | |
| 1167 | 12093 | int(M.cells.vertex(c,3) + 1), | |
| 1168 | ref | ||
| 1169 | ); | ||
| 1170 | } | ||
| 1171 | } | ||
| 1172 | } | ||
| 1173 | |||
| 1174 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
|
55 | if(nb_hexes > 0) { |
| 1175 | ✗ | GmfSetKwd( | |
| 1176 | mesh_file_handle, GmfHexahedra, int64_t(nb_hexes) | ||
| 1177 | ); | ||
| 1178 | ✗ | for(index_t c=0; c<M.cells.nb(); ++c) { | |
| 1179 | ✗ | if(M.cells.type(c) == MESH_HEX) { | |
| 1180 | index_t ref = | ||
| 1181 | ✗ | cell_region_.is_bound() ? cell_region_[c] : 0; | |
| 1182 | |||
| 1183 | // Swapping vertices 1<->0 and 4<->5 to | ||
| 1184 | // account for differences in the indexing | ||
| 1185 | // convetions in .mesh/.meshb files w.r.t. | ||
| 1186 | // geogram internal conventions. | ||
| 1187 | |||
| 1188 | ✗ | GmfSetLin( | |
| 1189 | mesh_file_handle, GmfHexahedra, | ||
| 1190 | ✗ | int(M.cells.vertex(c,1) + 1), | |
| 1191 | ✗ | int(M.cells.vertex(c,0) + 1), | |
| 1192 | ✗ | int(M.cells.vertex(c,2) + 1), | |
| 1193 | ✗ | int(M.cells.vertex(c,3) + 1), | |
| 1194 | ✗ | int(M.cells.vertex(c,5) + 1), | |
| 1195 | ✗ | int(M.cells.vertex(c,4) + 1), | |
| 1196 | ✗ | int(M.cells.vertex(c,6) + 1), | |
| 1197 | ✗ | int(M.cells.vertex(c,7) + 1), | |
| 1198 | ref | ||
| 1199 | ); | ||
| 1200 | } | ||
| 1201 | } | ||
| 1202 | } | ||
| 1203 | |||
| 1204 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
|
55 | if(nb_prisms > 0) { |
| 1205 | ✗ | GmfSetKwd(mesh_file_handle, GmfPrisms, int64_t(nb_prisms)); | |
| 1206 | ✗ | for(index_t c=0; c<M.cells.nb(); ++c) { | |
| 1207 | ✗ | if(M.cells.type(c) == MESH_PRISM) { | |
| 1208 | index_t ref = | ||
| 1209 | ✗ | cell_region_.is_bound() ? cell_region_[c] : 0; | |
| 1210 | ✗ | GmfSetLin( | |
| 1211 | mesh_file_handle, GmfPrisms, | ||
| 1212 | ✗ | int(M.cells.vertex(c,0) + 1), | |
| 1213 | ✗ | int(M.cells.vertex(c,1) + 1), | |
| 1214 | ✗ | int(M.cells.vertex(c,2) + 1), | |
| 1215 | ✗ | int(M.cells.vertex(c,3) + 1), | |
| 1216 | ✗ | int(M.cells.vertex(c,4) + 1), | |
| 1217 | ✗ | int(M.cells.vertex(c,5) + 1), | |
| 1218 | ref | ||
| 1219 | ); | ||
| 1220 | } | ||
| 1221 | } | ||
| 1222 | } | ||
| 1223 | |||
| 1224 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
|
55 | if(nb_pyramids > 0) { |
| 1225 | ✗ | GmfSetKwd( | |
| 1226 | mesh_file_handle, GmfPyramids, int64_t(nb_pyramids) | ||
| 1227 | ); | ||
| 1228 | ✗ | for(index_t c=0; c<M.cells.nb(); ++c) { | |
| 1229 | ✗ | if(M.cells.type(c) == MESH_PYRAMID) { | |
| 1230 | index_t ref = | ||
| 1231 | ✗ | cell_region_.is_bound() ? cell_region_[c] : 0; | |
| 1232 | ✗ | GmfSetLin( | |
| 1233 | mesh_file_handle, GmfPyramids, | ||
| 1234 | ✗ | int(M.cells.vertex(c,0) + 1), | |
| 1235 | ✗ | int(M.cells.vertex(c,1) + 1), | |
| 1236 | ✗ | int(M.cells.vertex(c,2) + 1), | |
| 1237 | ✗ | int(M.cells.vertex(c,3) + 1), | |
| 1238 | ✗ | int(M.cells.vertex(c,4) + 1), | |
| 1239 | ref | ||
| 1240 | ); | ||
| 1241 | } | ||
| 1242 | } | ||
| 1243 | } | ||
| 1244 | |||
| 1245 | } | ||
| 1246 | |||
| 1247 | 55 | unbind_attributes(); | |
| 1248 | 55 | GmfCloseMesh(mesh_file_handle); | |
| 1249 | |||
| 1250 | // If file is in ASCII, append parameters as comments | ||
| 1251 | // at the end of the file. | ||
| 1252 |
4/6✓ Branch 1 taken 55 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 55 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 10 times.
✓ Branch 8 taken 45 times.
|
55 | if(FileSystem::extension(filename) == "mesh") { |
| 1253 |
1/2✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
|
10 | FILE* f = fopen(filename.c_str(), "a"); |
| 1254 | 10 | std::vector<std::string> args; | |
| 1255 |
1/2✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
|
10 | CmdLine::get_args(args); |
| 1256 |
2/2✓ Branch 1 taken 367 times.
✓ Branch 2 taken 10 times.
|
377 | for(index_t i = 0; i < args.size(); i++) { |
| 1257 |
1/2✓ Branch 3 taken 367 times.
✗ Branch 4 not taken.
|
367 | fprintf(f, "# vorpaline %s\n", args[i].c_str()); |
| 1258 | } | ||
| 1259 |
1/2✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
|
10 | fclose(f); |
| 1260 | 10 | } | |
| 1261 | |||
| 1262 | 55 | return true; | |
| 1263 | } | ||
| 1264 | |||
| 1265 | protected: | ||
| 1266 | 77 | bool goto_elements(int64_t mesh_file_handle, int keyword) { | |
| 1267 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 77 times.
|
77 | if(!GmfGotoKwd(mesh_file_handle, keyword)) { |
| 1268 | ✗ | Logger::err("I/O") << "Failed to access " | |
| 1269 | ✗ | << keyword2name_[keyword] | |
| 1270 | ✗ | << " section" | |
| 1271 | ✗ | << std::endl; | |
| 1272 | ✗ | GmfCloseMesh(mesh_file_handle); | |
| 1273 | ✗ | unbind_attributes(); | |
| 1274 | ✗ | return false; | |
| 1275 | } | ||
| 1276 | 77 | return true; | |
| 1277 | } | ||
| 1278 | |||
| 1279 | 136830 | bool read_element( | |
| 1280 | int64_t mesh_file_handle, | ||
| 1281 | int keyword, int *v, int& ref, | ||
| 1282 | Mesh& M, index_t element_id | ||
| 1283 | ) { | ||
| 1284 | 136830 | index_t nbv = keyword2nbv_[keyword]; | |
| 1285 | 136830 | int res = 0; | |
| 1286 |
2/7✗ Branch 0 not taken.
✓ Branch 1 taken 126255 times.
✓ Branch 2 taken 10575 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
|
136830 | switch(nbv) { |
| 1287 | ✗ | case 2: | |
| 1288 | ✗ | res = GmfGetLin( | |
| 1289 | mesh_file_handle, keyword, | ||
| 1290 | &v[0], &v[1], &ref | ||
| 1291 | ); | ||
| 1292 | ✗ | break; | |
| 1293 | 126255 | case 3: | |
| 1294 | 126255 | res = GmfGetLin( | |
| 1295 | mesh_file_handle, keyword, | ||
| 1296 | &v[0], &v[1], &v[2], &ref | ||
| 1297 | ); | ||
| 1298 | 126255 | break; | |
| 1299 | 10575 | case 4: | |
| 1300 | 10575 | res = GmfGetLin( | |
| 1301 | mesh_file_handle, keyword, | ||
| 1302 | &v[0], &v[1], &v[2], &v[3], &ref | ||
| 1303 | ); | ||
| 1304 | 10575 | break; | |
| 1305 | ✗ | case 5: | |
| 1306 | ✗ | res = GmfGetLin( | |
| 1307 | mesh_file_handle, keyword, | ||
| 1308 | &v[0], &v[1], &v[2], &v[3], &v[4], | ||
| 1309 | &ref | ||
| 1310 | ); | ||
| 1311 | ✗ | break; | |
| 1312 | ✗ | case 6: | |
| 1313 | ✗ | res = GmfGetLin( | |
| 1314 | mesh_file_handle, keyword, | ||
| 1315 | &v[0], &v[1], &v[2], | ||
| 1316 | &v[3], &v[4], &v[5], | ||
| 1317 | &ref | ||
| 1318 | ); | ||
| 1319 | ✗ | break; | |
| 1320 | ✗ | case 8: | |
| 1321 | ✗ | res = GmfGetLin( | |
| 1322 | mesh_file_handle, keyword, | ||
| 1323 | &v[0], &v[1], &v[2], &v[3], | ||
| 1324 | &v[4], &v[5], &v[6], &v[7], | ||
| 1325 | &ref | ||
| 1326 | ); | ||
| 1327 | ✗ | break; | |
| 1328 | ✗ | default: | |
| 1329 | ✗ | geo_assert_not_reached; | |
| 1330 | } | ||
| 1331 | |||
| 1332 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 136829 times.
|
136830 | if(!res) { |
| 1333 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
2 | Logger::err("I/O") |
| 1334 | << "Failed to read " | ||
| 1335 | 1 | << keyword2name_[keyword] | |
| 1336 |
4/8✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
|
1 | << " #" << element_id |
| 1337 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | << std::endl; |
| 1338 | 1 | GmfCloseMesh(mesh_file_handle); | |
| 1339 | 1 | unbind_attributes(); | |
| 1340 | 1 | return false; | |
| 1341 | } | ||
| 1342 | |||
| 1343 |
2/2✓ Branch 0 taken 421061 times.
✓ Branch 1 taken 136828 times.
|
557889 | for(index_t lv=0; lv < nbv; ++lv) { |
| 1344 | 421061 | if( | |
| 1345 |
5/6✓ Branch 0 taken 421061 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 421060 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 421060 times.
|
842122 | v[lv] < 1 || |
| 1346 | 421061 | index_t(v[lv]) > M.vertices.nb() | |
| 1347 | ) { | ||
| 1348 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
2 | Logger::err("I/O") |
| 1349 | 1 | << "Error: " << keyword2name_[keyword] | |
| 1350 |
4/8✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
|
1 | <<" # " << element_id |
| 1351 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | << " references an invalid vertex: " << v[lv] |
| 1352 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | << std::endl; |
| 1353 | 1 | GmfCloseMesh(mesh_file_handle); | |
| 1354 | 1 | unbind_attributes(); | |
| 1355 | 1 | return false; | |
| 1356 | } | ||
| 1357 | } | ||
| 1358 | |||
| 1359 | 136828 | return true; | |
| 1360 | } | ||
| 1361 | |||
| 1362 | protected: | ||
| 1363 | std::string keyword2name_[GmfLastKeyword+1]; | ||
| 1364 | index_t keyword2nbv_[GmfLastKeyword+1]; | ||
| 1365 | }; | ||
| 1366 | |||
| 1367 | /************************************************************************/ | ||
| 1368 | |||
| 1369 | /** | ||
| 1370 | * \brief IO handler for the PLY file format | ||
| 1371 | * \details ASCII and binary, single and double precision are supported | ||
| 1372 | * \see http://en.wikipedia.org/wiki/PLY_(file_format) | ||
| 1373 | */ | ||
| 1374 | class GEOGRAM_API PLYIOHandler : public MeshIOHandler { | ||
| 1375 | public: | ||
| 1376 | |||
| 1377 | /** | ||
| 1378 | * \brief PLYIOHandler constructor. | ||
| 1379 | */ | ||
| 1380 | 5 | PLYIOHandler() { | |
| 1381 |
1/2✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
|
5 | geo_cite("WEB:rply"); |
| 1382 | 5 | } | |
| 1383 | |||
| 1384 | /** | ||
| 1385 | * \brief Helper class to read files in PLY format | ||
| 1386 | */ | ||
| 1387 | class PlyLoader { | ||
| 1388 | public: | ||
| 1389 | |||
| 1390 | /** | ||
| 1391 | * \brief Construts a new PlyLoader. | ||
| 1392 | * \param[in] filename name of the file to be loaded | ||
| 1393 | * \param[out] M the loaded mesh | ||
| 1394 | * \param[in] flags flags that determine which elements | ||
| 1395 | * and attributes should be read | ||
| 1396 | */ | ||
| 1397 | 4 | PlyLoader( | |
| 1398 | const std::string& filename, Mesh& M, const MeshIOFlags& flags | ||
| 1399 | 4 | ) : | |
| 1400 | 4 | mesh_(M), | |
| 1401 | 4 | filename_(filename), | |
| 1402 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | flags_(flags), |
| 1403 | 4 | current_vertex_(max_index_t()), | |
| 1404 | 4 | has_colors_(false), | |
| 1405 | 4 | color_mult_(1.0), | |
| 1406 | 4 | current_color_(max_index_t()), | |
| 1407 | 4 | tristrip_index_(0), | |
| 1408 |
1/2✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 | load_colors_(true) { |
| 1409 | 4 | } | |
| 1410 | |||
| 1411 | /** | ||
| 1412 | * \brief Specifies whether vertices colors should be loaded. | ||
| 1413 | */ | ||
| 1414 | void set_load_colors(bool x) { | ||
| 1415 | load_colors_ = x; | ||
| 1416 | } | ||
| 1417 | |||
| 1418 | /** | ||
| 1419 | * \brief Loads the file. | ||
| 1420 | * \return true on success, false otherwise | ||
| 1421 | */ | ||
| 1422 | 4 | bool load() { | |
| 1423 |
1/2✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 | p_ply ply = ply_open(filename_.c_str(), nullptr, 0, nullptr); |
| 1424 | |||
| 1425 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if(ply == nullptr) { |
| 1426 | ✗ | Logger::err("I/O") | |
| 1427 | ✗ | << "Could not open file: " << filename_ | |
| 1428 | ✗ | << std::endl; | |
| 1429 | ✗ | return false; | |
| 1430 | } | ||
| 1431 | |||
| 1432 |
2/4✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
|
4 | if(!ply_read_header(ply)) { |
| 1433 | ✗ | Logger::err("I/O") | |
| 1434 | ✗ | << "Invalid PLY header" | |
| 1435 | ✗ | << std::endl; | |
| 1436 | ✗ | ply_close(ply); | |
| 1437 | ✗ | return false; | |
| 1438 | } | ||
| 1439 | |||
| 1440 | 4 | current_vertex_ = 0; | |
| 1441 | 4 | current_color_ = 0; | |
| 1442 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | if(load_colors_) { |
| 1443 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | check_for_colors(ply); |
| 1444 | } else { | ||
| 1445 | ✗ | has_colors_ = false; | |
| 1446 | } | ||
| 1447 | |||
| 1448 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | long nvertices = ply_set_read_cb( |
| 1449 | ply, "vertex", "x", PlyLoader::vertex_cb, this, 0 | ||
| 1450 | ); | ||
| 1451 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | ply_set_read_cb( |
| 1452 | ply, "vertex", "y", PlyLoader::vertex_cb, this, 1 | ||
| 1453 | ); | ||
| 1454 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | ply_set_read_cb( |
| 1455 | ply, "vertex", "z", PlyLoader::vertex_cb, this, 2 | ||
| 1456 | ); | ||
| 1457 | |||
| 1458 | 4 | long nfaces = 0; | |
| 1459 | 4 | long ntstrips = 0; | |
| 1460 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | if(flags_.has_element(MESH_FACETS)) { |
| 1461 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | nfaces += ply_set_read_cb( |
| 1462 | ply, "face", "vertex_indices", | ||
| 1463 | PlyLoader::face_cb, this, 0 | ||
| 1464 | ); | ||
| 1465 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | nfaces += ply_set_read_cb( |
| 1466 | ply, "face", "vertex_index", | ||
| 1467 | PlyLoader::face_cb, this, 0 | ||
| 1468 | ); | ||
| 1469 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | ntstrips += ply_set_read_cb( |
| 1470 | ply, "tristrips", "vertex_indices", | ||
| 1471 | PlyLoader::tristrip_cb, this, 0 | ||
| 1472 | ); | ||
| 1473 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | ntstrips += ply_set_read_cb( |
| 1474 | ply, "tristrips", "vertex_index", | ||
| 1475 | PlyLoader::tristrip_cb, this, 0 | ||
| 1476 | ); | ||
| 1477 | } | ||
| 1478 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if(nvertices == 0) { |
| 1479 | ✗ | Logger::err("I/O") | |
| 1480 | ✗ | << "File contains no vertices" << std::endl; | |
| 1481 | ✗ | ply_close(ply); | |
| 1482 | ✗ | return false; | |
| 1483 | } | ||
| 1484 | |||
| 1485 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | mesh_.vertices.create_vertices(index_t(nvertices)); |
| 1486 | |||
| 1487 | 4 | geo_argused(nfaces); | |
| 1488 | 4 | geo_argused(ntstrips); | |
| 1489 | // TODO: here we could create / reserve facets | ||
| 1490 | |||
| 1491 |
3/4✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 1 times.
|
4 | if(!ply_read(ply)) { |
| 1492 |
2/4✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
|
6 | Logger::err("I/O") |
| 1493 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | << "Problem occurred while parsing PLY file" |
| 1494 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | << std::endl; |
| 1495 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | ply_close(ply); |
| 1496 | 3 | return false; | |
| 1497 | } | ||
| 1498 | |||
| 1499 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | ply_close(ply); |
| 1500 | |||
| 1501 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if(current_vertex_ != mesh_.vertices.nb()) { |
| 1502 | ✗ | Logger::err("I/O") | |
| 1503 | ✗ | << "File does not contain enough vertex data" | |
| 1504 | ✗ | << std::endl; | |
| 1505 | ✗ | return false; | |
| 1506 | } | ||
| 1507 | |||
| 1508 | 1 | if( | |
| 1509 |
2/6✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
|
1 | has_colors_ && |
| 1510 | ✗ | current_color_ != mesh_.vertices.nb() | |
| 1511 | ) { | ||
| 1512 | ✗ | Logger::err("I/O") | |
| 1513 | ✗ | << "File does not contain enough color data" | |
| 1514 | ✗ | << std::endl; | |
| 1515 | ✗ | return false; | |
| 1516 | } | ||
| 1517 | |||
| 1518 | 1 | return true; | |
| 1519 | } | ||
| 1520 | |||
| 1521 | protected: | ||
| 1522 | /** | ||
| 1523 | * \brief Detects whether the input file has colors | ||
| 1524 | * \param[in] ply the p_ply handle to the file | ||
| 1525 | */ | ||
| 1526 | 4 | void check_for_colors(p_ply ply) { | |
| 1527 | 4 | p_ply_element element = nullptr; | |
| 1528 | |||
| 1529 | 4 | bool has_r = false; | |
| 1530 | 4 | bool has_g = false; | |
| 1531 | 4 | bool has_b = false; | |
| 1532 | |||
| 1533 | 4 | bool has_red = false; | |
| 1534 | 4 | bool has_green = false; | |
| 1535 | 4 | bool has_blue = false; | |
| 1536 | |||
| 1537 | for(;;) { | ||
| 1538 |
1/2✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
|
12 | element = ply_get_next_element(ply, element); |
| 1539 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 8 times.
|
12 | if(element == nullptr) { |
| 1540 | 4 | break; | |
| 1541 | } | ||
| 1542 | 8 | const char* elt_name = nullptr; | |
| 1543 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | ply_get_element_info(element, &elt_name, nullptr); |
| 1544 | |||
| 1545 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
|
8 | if(!strcmp(elt_name, "vertex")) { |
| 1546 | 4 | p_ply_property property = nullptr; | |
| 1547 | for(;;) { | ||
| 1548 |
1/2✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
|
16 | property = ply_get_next_property(element, property); |
| 1549 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 12 times.
|
16 | if(property == nullptr) { |
| 1550 | 4 | break; | |
| 1551 | } | ||
| 1552 | 12 | const char* prop_name = nullptr; | |
| 1553 |
1/2✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
|
12 | ply_get_property_info( |
| 1554 | property, &prop_name, nullptr, nullptr, nullptr | ||
| 1555 | ); | ||
| 1556 |
2/4✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
|
12 | has_r = has_r || !strcmp(prop_name, "r"); |
| 1557 |
2/4✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
|
12 | has_g = has_g || !strcmp(prop_name, "g"); |
| 1558 |
2/4✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
|
12 | has_b = has_b || !strcmp(prop_name, "b"); |
| 1559 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
24 | has_red = has_red || |
| 1560 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | !strcmp(prop_name, "red"); |
| 1561 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
24 | has_green = has_green || |
| 1562 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | !strcmp(prop_name, "green"); |
| 1563 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
24 | has_blue = has_blue || |
| 1564 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | !strcmp(prop_name, "blue"); |
| 1565 | 12 | } | |
| 1566 | } | ||
| 1567 | 8 | } | |
| 1568 | |||
| 1569 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
4 | if(has_r && has_g && has_b) { |
| 1570 | ✗ | has_colors_ = true; | |
| 1571 | ✗ | color_mult_ = 1.0; | |
| 1572 | ✗ | ply_set_read_cb( | |
| 1573 | ply, "vertex", "r", PlyLoader::color_cb, this, 0 | ||
| 1574 | ); | ||
| 1575 | ✗ | ply_set_read_cb( | |
| 1576 | ply, "vertex", "g", PlyLoader::color_cb, this, 1 | ||
| 1577 | ); | ||
| 1578 | ✗ | ply_set_read_cb( | |
| 1579 | ply, "vertex", "b", PlyLoader::color_cb, this, 2 | ||
| 1580 | ); | ||
| 1581 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
4 | } else if(has_red && has_green && has_blue) { |
| 1582 | ✗ | has_colors_ = true; | |
| 1583 | ✗ | color_mult_ = 1.0 / 255.0; | |
| 1584 | ✗ | ply_set_read_cb( | |
| 1585 | ply, "vertex", "red", PlyLoader::color_cb, this, 0 | ||
| 1586 | ); | ||
| 1587 | ✗ | ply_set_read_cb( | |
| 1588 | ply, "vertex", "green", PlyLoader::color_cb, this, 1 | ||
| 1589 | ); | ||
| 1590 | ✗ | ply_set_read_cb( | |
| 1591 | ply, "vertex", "blue", PlyLoader::color_cb, this, 2 | ||
| 1592 | ); | ||
| 1593 | } else { | ||
| 1594 | 4 | has_colors_ = false; | |
| 1595 | } | ||
| 1596 | |||
| 1597 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | if(!has_colors_) { |
| 1598 | 4 | return; | |
| 1599 | } | ||
| 1600 | |||
| 1601 | ✗ | vertex_color_.bind_if_is_defined( | |
| 1602 | ✗ | mesh_.vertices.attributes(), "color" | |
| 1603 | ); | ||
| 1604 | ✗ | if(vertex_color_.is_bound() && | |
| 1605 | ✗ | vertex_color_.dimension() != 3 | |
| 1606 | ) { | ||
| 1607 | ✗ | Logger::warn("PLY") | |
| 1608 | << "Mesh already has a color attribute " | ||
| 1609 | ✗ | << "that is not of dimension 3" | |
| 1610 | ✗ | << std::endl; | |
| 1611 | ✗ | has_colors_ = false; | |
| 1612 | ✗ | return; | |
| 1613 | } | ||
| 1614 | ✗ | if(!vertex_color_.is_bound()) { | |
| 1615 | ✗ | vertex_color_.create_vector_attribute( | |
| 1616 | ✗ | mesh_.vertices.attributes(), | |
| 1617 | ✗ | "color", | |
| 1618 | 3 | ||
| 1619 | ); | ||
| 1620 | } | ||
| 1621 | } | ||
| 1622 | |||
| 1623 | /** | ||
| 1624 | * \brief Gets the PlyLoader associated with | ||
| 1625 | * an opaque p_ply_argument. | ||
| 1626 | * \details Used to pass a Plyloader through libply callbacks | ||
| 1627 | * \param[in] argument the opaque p_ply_argument | ||
| 1628 | * \return the PlyLoader associated with \p argument | ||
| 1629 | */ | ||
| 1630 | 366 | static PlyLoader* loader(p_ply_argument argument) { | |
| 1631 | 366 | PlyLoader* result = nullptr; | |
| 1632 |
1/2✓ Branch 1 taken 366 times.
✗ Branch 2 not taken.
|
366 | ply_get_argument_user_data( |
| 1633 | argument, (void**) (&result), nullptr | ||
| 1634 | ); | ||
| 1635 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 366 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
366 | geo_debug_assert(result != nullptr); |
| 1636 | 366 | return result; | |
| 1637 | } | ||
| 1638 | |||
| 1639 | /** | ||
| 1640 | * \brief The vertex callback, called for each vertex | ||
| 1641 | * of the input file. | ||
| 1642 | * \param[in] argument the generic opaque argument | ||
| 1643 | * (from which this PlyLoader is retrieved). | ||
| 1644 | * \return callback status code, zero for errors, | ||
| 1645 | * non-zero for success. | ||
| 1646 | */ | ||
| 1647 | 132 | static int vertex_cb(p_ply_argument argument) { | |
| 1648 | 132 | return loader(argument)->add_vertex_data(argument); | |
| 1649 | } | ||
| 1650 | |||
| 1651 | /** | ||
| 1652 | * \brief The facet callback, called for each facet | ||
| 1653 | * of the input file. | ||
| 1654 | * \param[in] argument the generic opaque argument | ||
| 1655 | * (from which this PlyLoader is retrieved). | ||
| 1656 | * \return callback status code, zero for errors, | ||
| 1657 | * non-zero for success. | ||
| 1658 | */ | ||
| 1659 | 234 | static int face_cb(p_ply_argument argument) { | |
| 1660 | 234 | return loader(argument)->add_face_data(argument); | |
| 1661 | } | ||
| 1662 | |||
| 1663 | /** | ||
| 1664 | * \brief The triangle strip callback, | ||
| 1665 | * called for each triangle strip of the input file. | ||
| 1666 | * \param[in] argument the generic opaque argument | ||
| 1667 | * (from which this PlyLoader is retrieved). | ||
| 1668 | * \return callback status code, zero for errors, | ||
| 1669 | * non-zero for success. | ||
| 1670 | */ | ||
| 1671 | ✗ | static int tristrip_cb(p_ply_argument argument) { | |
| 1672 | ✗ | return loader(argument)->add_tristrip_data(argument); | |
| 1673 | } | ||
| 1674 | |||
| 1675 | /** | ||
| 1676 | * \brief The color callback, called for | ||
| 1677 | * each color data of the input file. | ||
| 1678 | * \param[in] argument the generic opaque argument | ||
| 1679 | * (from which this PlyLoader is retrieved). | ||
| 1680 | * \return callback status code, zero for errors, | ||
| 1681 | * non-zero for success. | ||
| 1682 | */ | ||
| 1683 | ✗ | static int color_cb(p_ply_argument argument) { | |
| 1684 | ✗ | return loader(argument)->add_color_data(argument); | |
| 1685 | } | ||
| 1686 | |||
| 1687 | /** | ||
| 1688 | * \brief Decodes vertex data from a generic callback argument. | ||
| 1689 | * \param[in] argument the generic callback argument. | ||
| 1690 | * \return callback status code, | ||
| 1691 | * zero for errors, non-zero for success. | ||
| 1692 | */ | ||
| 1693 | 132 | int add_vertex_data(p_ply_argument argument) { | |
| 1694 | long coord; | ||
| 1695 |
1/2✓ Branch 1 taken 132 times.
✗ Branch 2 not taken.
|
132 | ply_get_argument_user_data(argument, nullptr, &coord); |
| 1696 |
2/2✓ Branch 0 taken 44 times.
✓ Branch 1 taken 88 times.
|
132 | if(coord == 0) { |
| 1697 |
2/8✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 44 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
|
44 | geo_debug_assert(mesh_.vertices.dimension() >= 3); |
| 1698 | 44 | if( | |
| 1699 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 44 times.
|
44 | current_vertex_ >= mesh_.vertices.nb() |
| 1700 | ) { | ||
| 1701 | ✗ | Logger::err("I/O") | |
| 1702 | ✗ | << "File contains extraneous vertex data" | |
| 1703 | ✗ | << std::endl; | |
| 1704 | ✗ | return 0; | |
| 1705 | } | ||
| 1706 | 44 | current_vertex_++; | |
| 1707 | } | ||
| 1708 | |||
| 1709 |
5/6✓ Branch 0 taken 88 times.
✓ Branch 1 taken 44 times.
✓ Branch 2 taken 44 times.
✓ Branch 3 taken 44 times.
✓ Branch 4 taken 44 times.
✗ Branch 5 not taken.
|
132 | if(coord == 0 || coord == 1 || coord == 2) { |
| 1710 | // Note: current_vertex_ was incremented before, | ||
| 1711 | // so we need to index by current_vertex_ - 1 | ||
| 1712 |
2/4✓ Branch 1 taken 132 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 132 times.
|
132 | if(mesh_.vertices.single_precision()) { |
| 1713 | ✗ | mesh_.vertices.single_precision_point_ptr( | |
| 1714 | ✗ | current_vertex_-1 | |
| 1715 | ✗ | )[coord] = float(ply_get_argument_value(argument)); | |
| 1716 | } else { | ||
| 1717 | 264 | mesh_.vertices.point_ptr( | |
| 1718 | 132 | current_vertex_-1 | |
| 1719 |
2/4✓ Branch 1 taken 132 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 132 times.
✗ Branch 5 not taken.
|
132 | )[coord] = ply_get_argument_value(argument); |
| 1720 | } | ||
| 1721 | 132 | return 1; | |
| 1722 | } | ||
| 1723 | |||
| 1724 | ✗ | Logger::err("I/O") | |
| 1725 | ✗ | << "In vertex #" << current_vertex_ | |
| 1726 | ✗ | << ": invalid coordinate index: " << coord | |
| 1727 | ✗ | << std::endl; | |
| 1728 | ✗ | return 0; | |
| 1729 | } | ||
| 1730 | |||
| 1731 | /** | ||
| 1732 | * \brief Decodes facet data from a generic callback argument. | ||
| 1733 | * \param[in] argument the generic callback argument. | ||
| 1734 | * \return callback status code, zero for errors, | ||
| 1735 | * non-zero for success. | ||
| 1736 | */ | ||
| 1737 | 234 | int add_face_data(p_ply_argument argument) { | |
| 1738 | long length, value_index; | ||
| 1739 |
1/2✓ Branch 1 taken 234 times.
✗ Branch 2 not taken.
|
234 | ply_get_argument_property( |
| 1740 | argument, nullptr, &length, &value_index | ||
| 1741 | ); | ||
| 1742 |
2/2✓ Branch 0 taken 59 times.
✓ Branch 1 taken 175 times.
|
234 | if(value_index < 0) { |
| 1743 | // Ignore negative values - | ||
| 1744 | // this is not an error! (facet markers) | ||
| 1745 | 59 | return 1; | |
| 1746 | } | ||
| 1747 | |||
| 1748 | index_t vertex_index = index_t( | ||
| 1749 |
1/2✓ Branch 1 taken 175 times.
✗ Branch 2 not taken.
|
175 | ply_get_argument_value(argument) |
| 1750 | 175 | ); | |
| 1751 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 175 times.
|
175 | if(index_t(vertex_index) >= mesh_.vertices.nb()) { |
| 1752 | ✗ | Logger::err("I/O") | |
| 1753 | ✗ | << "Facet corner #" << mesh_.facets.nb() | |
| 1754 | ✗ | << " references an invalid vertex: " | |
| 1755 | ✗ | << vertex_index | |
| 1756 | ✗ | << std::endl; | |
| 1757 | ✗ | return 0; | |
| 1758 | } | ||
| 1759 | |||
| 1760 |
2/2✓ Branch 0 taken 58 times.
✓ Branch 1 taken 117 times.
|
175 | if(value_index == 0) { |
| 1761 |
1/2✓ Branch 1 taken 58 times.
✗ Branch 2 not taken.
|
58 | begin_facet(); |
| 1762 | } | ||
| 1763 |
1/2✓ Branch 1 taken 175 times.
✗ Branch 2 not taken.
|
175 | add_vertex_to_facet(vertex_index); |
| 1764 |
2/2✓ Branch 0 taken 58 times.
✓ Branch 1 taken 117 times.
|
175 | if(value_index == length - 1) { |
| 1765 |
1/2✓ Branch 1 taken 58 times.
✗ Branch 2 not taken.
|
58 | end_facet(); |
| 1766 | } | ||
| 1767 | 175 | return 1; | |
| 1768 | } | ||
| 1769 | |||
| 1770 | /** | ||
| 1771 | * \brief Decodes triangle strip data from a | ||
| 1772 | * generic callback argument. | ||
| 1773 | * \param[in] argument the generic callback argument. | ||
| 1774 | * \return callback status code, zero for errors, | ||
| 1775 | * non-zero for success. | ||
| 1776 | */ | ||
| 1777 | ✗ | int add_tristrip_data(p_ply_argument argument) { | |
| 1778 | long length, value_index; | ||
| 1779 | ✗ | ply_get_argument_property( | |
| 1780 | argument, nullptr, &length, &value_index | ||
| 1781 | ); | ||
| 1782 | ✗ | if(value_index < 0) { | |
| 1783 | // Ignore negative values - this is not an error! | ||
| 1784 | ✗ | return 1; | |
| 1785 | } | ||
| 1786 | |||
| 1787 | // NOTE: negative vertex_index values have | ||
| 1788 | // a special meaning here: | ||
| 1789 | // they tell the loader to start a new strip | ||
| 1790 | |||
| 1791 | signed_index_t vertex_index = signed_index_t( | ||
| 1792 | ✗ | ply_get_argument_value(argument) | |
| 1793 | ✗ | ); | |
| 1794 | ✗ | if(vertex_index >= | |
| 1795 | ✗ | signed_index_t(mesh_.vertices.nb()) | |
| 1796 | ) { | ||
| 1797 | ✗ | Logger::err("I/O") | |
| 1798 | ✗ | << "Invalid vertex reference in tristrip: " | |
| 1799 | ✗ | << vertex_index | |
| 1800 | ✗ | << std::endl; | |
| 1801 | ✗ | return 0; | |
| 1802 | } | ||
| 1803 | |||
| 1804 | ✗ | if(value_index == 0) { | |
| 1805 | ✗ | begin_tristrip(); | |
| 1806 | } | ||
| 1807 | ✗ | if(vertex_index >= 0) { | |
| 1808 | ✗ | add_to_tristrip(index_t(vertex_index)); | |
| 1809 | } else { | ||
| 1810 | ✗ | end_tristrip(); | |
| 1811 | ✗ | begin_tristrip(); | |
| 1812 | } | ||
| 1813 | ✗ | if(value_index == length - 1) { | |
| 1814 | ✗ | end_tristrip(); | |
| 1815 | } | ||
| 1816 | ✗ | return 1; | |
| 1817 | } | ||
| 1818 | |||
| 1819 | /** | ||
| 1820 | * \brief Starts a new facet. | ||
| 1821 | */ | ||
| 1822 | 58 | void begin_facet() { | |
| 1823 | 58 | facet_vertices_.resize(0); | |
| 1824 | 58 | } | |
| 1825 | |||
| 1826 | /** | ||
| 1827 | * \brief Adds a vertex to the current facet. | ||
| 1828 | * \param[in] v the index of the vertex to be added | ||
| 1829 | */ | ||
| 1830 | 175 | void add_vertex_to_facet(index_t v) { | |
| 1831 | 175 | facet_vertices_.push_back(v); | |
| 1832 | 175 | } | |
| 1833 | |||
| 1834 | |||
| 1835 | /** | ||
| 1836 | * \brief Terminates the currently constructed | ||
| 1837 | * facet. | ||
| 1838 | */ | ||
| 1839 | 58 | void end_facet() { | |
| 1840 | 58 | index_t f = mesh_.facets.create_polygon(facet_vertices_.size()); | |
| 1841 |
2/2✓ Branch 1 taken 175 times.
✓ Branch 2 taken 58 times.
|
233 | for(index_t lv=0; lv<facet_vertices_.size(); ++lv) { |
| 1842 | 175 | mesh_.facets.set_vertex(f,lv,facet_vertices_[lv]); | |
| 1843 | } | ||
| 1844 | 58 | } | |
| 1845 | |||
| 1846 | /** | ||
| 1847 | * \brief Starts a new triangle strip. | ||
| 1848 | */ | ||
| 1849 | ✗ | void begin_tristrip() { | |
| 1850 | ✗ | tristrip_index_ = 0; | |
| 1851 | ✗ | } | |
| 1852 | |||
| 1853 | /** | ||
| 1854 | * \brief Terminates the current triangle strip. | ||
| 1855 | */ | ||
| 1856 | ✗ | void end_tristrip() { | |
| 1857 | ✗ | } | |
| 1858 | |||
| 1859 | /** | ||
| 1860 | * \brief Adds a vertex to the current triangle strip. | ||
| 1861 | * \param[in] vertex_index the index of the vertex | ||
| 1862 | */ | ||
| 1863 | ✗ | void add_to_tristrip(index_t vertex_index) { | |
| 1864 | ✗ | if(tristrip_index_ >= 2) { | |
| 1865 | ✗ | mesh_.facets.create_triangle( | |
| 1866 | tristrip_points_[0], | ||
| 1867 | tristrip_points_[1], | ||
| 1868 | vertex_index | ||
| 1869 | ); | ||
| 1870 | } | ||
| 1871 | ✗ | tristrip_points_[tristrip_index_ & 1] = vertex_index; | |
| 1872 | ✗ | tristrip_index_++; | |
| 1873 | ✗ | } | |
| 1874 | |||
| 1875 | /** | ||
| 1876 | * \brief Adds color data to the current vertex | ||
| 1877 | * \param[in] argument the generic callback argument | ||
| 1878 | * \return callback status code, zero for errors, | ||
| 1879 | * non-zero for success. | ||
| 1880 | */ | ||
| 1881 | ✗ | int add_color_data(p_ply_argument argument) { | |
| 1882 | long coord; | ||
| 1883 | ✗ | ply_get_argument_user_data(argument, nullptr, &coord); | |
| 1884 | ✗ | if(coord == 0) { | |
| 1885 | ✗ | if(current_color_ >= mesh_.vertices.nb()) { | |
| 1886 | ✗ | Logger::err("I/O") | |
| 1887 | ✗ | << "File contains extraneous color data" | |
| 1888 | ✗ | << std::endl; | |
| 1889 | ✗ | return 0; | |
| 1890 | } | ||
| 1891 | ✗ | current_color_++; | |
| 1892 | } | ||
| 1893 | |||
| 1894 | ✗ | if(coord == 0 || coord == 1 || coord == 2) { | |
| 1895 | double value = | ||
| 1896 | ✗ | double(ply_get_argument_value(argument)) * color_mult_; | |
| 1897 | // (note: current_color_ - 1 because it was incremented before) | ||
| 1898 | ✗ | vertex_color_[3*(current_color_ - 1) + index_t(coord)] = value; | |
| 1899 | ✗ | return 1; | |
| 1900 | } | ||
| 1901 | |||
| 1902 | ✗ | Logger::err("I/O") | |
| 1903 | ✗ | << "In vertex #" << current_color_ | |
| 1904 | ✗ | << ": invalid color index: " << coord | |
| 1905 | ✗ | << std::endl; | |
| 1906 | ✗ | return 0; | |
| 1907 | } | ||
| 1908 | |||
| 1909 | protected: | ||
| 1910 | Mesh& mesh_; | ||
| 1911 | std::string filename_; | ||
| 1912 | MeshIOFlags flags_; | ||
| 1913 | |||
| 1914 | index_t current_vertex_; | ||
| 1915 | |||
| 1916 | bool has_colors_; | ||
| 1917 | double color_mult_; | ||
| 1918 | index_t current_color_; | ||
| 1919 | |||
| 1920 | index_t tristrip_points_[2]; | ||
| 1921 | index_t tristrip_index_; | ||
| 1922 | |||
| 1923 | bool load_colors_; | ||
| 1924 | |||
| 1925 | vector<index_t> facet_vertices_; | ||
| 1926 | |||
| 1927 | Attribute<double> vertex_color_; | ||
| 1928 | }; | ||
| 1929 | |||
| 1930 | |||
| 1931 | 4 | bool load( | |
| 1932 | const std::string& filename, Mesh& M, | ||
| 1933 | const MeshIOFlags& ioflags = MeshIOFlags() | ||
| 1934 | ) override { | ||
| 1935 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | PlyLoader loader(filename, M, ioflags); |
| 1936 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
8 | return loader.load(); |
| 1937 | 4 | } | |
| 1938 | |||
| 1939 | 1 | bool save( | |
| 1940 | const Mesh& M, const std::string& filename, | ||
| 1941 | const MeshIOFlags& ioflags | ||
| 1942 | ) override { | ||
| 1943 |
1/2✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | p_ply oply = ply_create( |
| 1944 | filename.c_str(), | ||
| 1945 |
3/6✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
|
2 | (CmdLine::get_arg_bool("sys:ascii") ? PLY_ASCII : PLY_LITTLE_ENDIAN), |
| 1946 | nullptr, 0, nullptr | ||
| 1947 | ); | ||
| 1948 | |||
| 1949 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if(oply == nullptr) { |
| 1950 | ✗ | return false; | |
| 1951 | } | ||
| 1952 | |||
| 1953 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | Attribute<double> vertex_color; |
| 1954 |
1/2✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | vertex_color.bind_if_is_defined( |
| 1955 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
2 | M.vertices.attributes(), "color" |
| 1956 | ); | ||
| 1957 |
2/6✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
|
1 | if(vertex_color.is_bound() && vertex_color.dimension() != 3) { |
| 1958 | ✗ | Logger::warn("IO") | |
| 1959 | ✗ | << "Mesh has vertex colors but attribut dim is not 3 (ignoring them)" | |
| 1960 | ✗ | << std::endl; | |
| 1961 | ✗ | vertex_color.unbind(); | |
| 1962 | } | ||
| 1963 | |||
| 1964 | // Create element and properties for vertices | ||
| 1965 | 1 | e_ply_type coord_type = PLY_FLOAT; | |
| 1966 | 1 | e_ply_type color_type = PLY_UINT8; | |
| 1967 |
1/2✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | ply_add_element(oply, "vertex", long(M.vertices.nb())); |
| 1968 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | ply_add_property(oply, "x", coord_type, coord_type, coord_type); |
| 1969 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | ply_add_property(oply, "y", coord_type, coord_type, coord_type); |
| 1970 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | ply_add_property(oply, "z", coord_type, coord_type, coord_type); |
| 1971 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if(vertex_color.is_bound()) { |
| 1972 | ✗ | ply_add_property(oply, "red", color_type, color_type, color_type); | |
| 1973 | ✗ | ply_add_property(oply, "green", color_type, color_type, color_type); | |
| 1974 | ✗ | ply_add_property(oply, "blue", color_type, color_type, color_type); | |
| 1975 | } | ||
| 1976 | |||
| 1977 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | if(ioflags.has_element(MESH_FACETS)) { |
| 1978 | // Create element and properties for facets | ||
| 1979 | // (determine best index types) | ||
| 1980 | 1 | index_t max_facet_size = 0; | |
| 1981 |
2/2✓ Branch 1 taken 20 times.
✓ Branch 2 taken 1 times.
|
21 | for(index_t f = 0; f < M.facets.nb(); ++f) { |
| 1982 | 40 | max_facet_size = std::max( | |
| 1983 |
1/2✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
|
20 | max_facet_size, M.facets.nb_vertices(f) |
| 1984 | ); | ||
| 1985 | } | ||
| 1986 | 1 | e_ply_type facet_len_type = PLY_UCHAR; | |
| 1987 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if(max_facet_size > 65535) { |
| 1988 | ✗ | facet_len_type = PLY_UINT; | |
| 1989 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | } else if(max_facet_size > 255) { |
| 1990 | ✗ | facet_len_type = PLY_USHORT; | |
| 1991 | } | ||
| 1992 | 1 | e_ply_type facet_idx_type = PLY_INT; | |
| 1993 |
1/2✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | ply_add_element(oply, "face", long(M.facets.nb())); |
| 1994 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | ply_add_property( |
| 1995 | oply, "vertex_indices", | ||
| 1996 | PLY_LIST, facet_len_type, facet_idx_type | ||
| 1997 | ); | ||
| 1998 | } | ||
| 1999 | |||
| 2000 | 1 | std::vector<std::string> args; | |
| 2001 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | CmdLine::get_args(args); |
| 2002 |
2/2✓ Branch 1 taken 88 times.
✓ Branch 2 taken 1 times.
|
89 | for(index_t i = 0; i < args.size(); i++) { |
| 2003 |
2/4✓ Branch 2 taken 88 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 88 times.
✗ Branch 7 not taken.
|
88 | ply_add_comment(oply, ("vorpaline " + args[i]).c_str()); |
| 2004 | } | ||
| 2005 | |||
| 2006 | // Write header | ||
| 2007 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
|
1 | if(!ply_write_header(oply)) { |
| 2008 | ✗ | ply_close(oply); | |
| 2009 | ✗ | return false; | |
| 2010 | } | ||
| 2011 | |||
| 2012 | // Write vertices | ||
| 2013 |
2/2✓ Branch 1 taken 12 times.
✓ Branch 2 taken 1 times.
|
13 | for(index_t v = 0; v < M.vertices.nb(); ++v) { |
| 2014 | double xyz[3]; | ||
| 2015 |
1/2✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
|
12 | get_mesh_point(M, v, xyz, 3); |
| 2016 |
2/2✓ Branch 0 taken 36 times.
✓ Branch 1 taken 12 times.
|
48 | for(index_t coord = 0; coord < 3; coord++) { |
| 2017 |
1/2✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
|
36 | ply_write(oply, xyz[coord]); |
| 2018 | } | ||
| 2019 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
|
12 | if(vertex_color.is_bound()) { |
| 2020 | ✗ | const double* rgb = &vertex_color[v*3]; | |
| 2021 | ✗ | for(index_t coord = 0; coord < 3; coord++) { | |
| 2022 | ✗ | ply_write(oply, Numeric::uint8(255.0*rgb[coord])); | |
| 2023 | } | ||
| 2024 | } | ||
| 2025 | } | ||
| 2026 | |||
| 2027 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | if(ioflags.has_element(MESH_FACETS)) { |
| 2028 | // Write facets | ||
| 2029 |
2/2✓ Branch 1 taken 20 times.
✓ Branch 2 taken 1 times.
|
21 | for(index_t f = 0; f < M.facets.nb(); ++f) { |
| 2030 |
2/4✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
|
20 | ply_write(oply, double(M.facets.nb_vertices(f))); |
| 2031 |
1/2✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
|
80 | for(index_t c = M.facets.corners_begin(f); |
| 2032 |
3/4✓ Branch 1 taken 80 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 60 times.
✓ Branch 4 taken 20 times.
|
80 | c < M.facets.corners_end(f); ++c |
| 2033 | ) { | ||
| 2034 |
2/4✓ Branch 1 taken 60 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 60 times.
✗ Branch 5 not taken.
|
60 | ply_write(oply, double(M.facet_corners.vertex(c))); |
| 2035 | } | ||
| 2036 | } | ||
| 2037 | } | ||
| 2038 | |||
| 2039 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | ply_close(oply); |
| 2040 | 1 | return true; | |
| 2041 | 1 | } | |
| 2042 | }; | ||
| 2043 | |||
| 2044 | /************************************************************************/ | ||
| 2045 | |||
| 2046 | /** | ||
| 2047 | * \brief IO handler for the OFF file format | ||
| 2048 | * \see http://www.geomview.org/docs/html/OFF.html | ||
| 2049 | */ | ||
| 2050 | class GEOGRAM_API OFFIOHandler : public MeshIOHandler { | ||
| 2051 | public: | ||
| 2052 | /** | ||
| 2053 | * \brief Loads a mesh from a file in OFF format. | ||
| 2054 | * \param[in] filename name of the file | ||
| 2055 | * \param[out] M the loaded mesh | ||
| 2056 | * \param[in] ioflags specifies which attributes | ||
| 2057 | * and elements should be read | ||
| 2058 | * \return true on success, false otherwise | ||
| 2059 | */ | ||
| 2060 | 24 | bool load( | |
| 2061 | const std::string& filename, Mesh& M, | ||
| 2062 | const MeshIOFlags& ioflags | ||
| 2063 | ) override { | ||
| 2064 | 24 | geo_argused(ioflags); | |
| 2065 | |||
| 2066 | // Note: Vertices indexes start by 0 in off format. | ||
| 2067 | |||
| 2068 |
1/2✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
|
24 | LineInput in(filename); |
| 2069 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
|
24 | if(!in.OK()) { |
| 2070 | ✗ | return false; | |
| 2071 | } | ||
| 2072 | |||
| 2073 |
2/4✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 24 times.
|
24 | if(!in.get_line()) { |
| 2074 | ✗ | Logger::err("I/O") | |
| 2075 | ✗ | << "Unexpected end of file" | |
| 2076 | ✗ | << std::endl; | |
| 2077 | ✗ | return false; | |
| 2078 | } | ||
| 2079 |
1/2✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
|
24 | in.get_fields(); |
| 2080 |
4/8✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 24 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 24 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 24 times.
|
24 | if(in.nb_fields() == 0 || !in.field_matches(0, "OFF")) { |
| 2081 | ✗ | Logger::err("I/O") | |
| 2082 | ✗ | << "Line " << in.line_number() | |
| 2083 | ✗ | << ": unrecognized header" | |
| 2084 | ✗ | << std::endl; | |
| 2085 | ✗ | return false; | |
| 2086 | } | ||
| 2087 | |||
| 2088 |
2/4✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 24 times.
|
24 | if(!in.get_line()) { |
| 2089 | ✗ | Logger::err("I/O") | |
| 2090 | ✗ | << "Line " << in.line_number() | |
| 2091 | ✗ | << ": unexpected end of file" | |
| 2092 | ✗ | << std::endl; | |
| 2093 | ✗ | return false; | |
| 2094 | } | ||
| 2095 |
1/2✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
|
24 | in.get_fields(); |
| 2096 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
|
24 | if(in.nb_fields() != 3) { |
| 2097 | ✗ | Logger::err("I/O") | |
| 2098 | ✗ | << "Line " << in.line_number() | |
| 2099 | ✗ | << ": unrecognized header" | |
| 2100 | ✗ | << std::endl; | |
| 2101 | ✗ | return false; | |
| 2102 | } | ||
| 2103 | |||
| 2104 |
1/2✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
|
24 | index_t nb_vertices = in.field_as_uint(0); |
| 2105 | // second field is nb edges (unused) | ||
| 2106 | // index_t nb_facets = in.field_as_uint(2); | ||
| 2107 | |||
| 2108 |
1/2✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
|
24 | M.vertices.create_vertices(nb_vertices); |
| 2109 | // TODO: reserve facets | ||
| 2110 | |||
| 2111 |
2/2✓ Branch 0 taken 66903 times.
✓ Branch 1 taken 22 times.
|
66925 | for(index_t i = 0; i < nb_vertices; i++) { |
| 2112 | do { | ||
| 2113 |
2/4✓ Branch 1 taken 66903 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 66903 times.
|
66903 | if(!in.get_line()) { |
| 2114 | ✗ | Logger::err("I/O") | |
| 2115 | ✗ | << "Line " << in.line_number() | |
| 2116 | ✗ | << ": unexpected end of file" | |
| 2117 | ✗ | << std::endl; | |
| 2118 | 1 | return false; | |
| 2119 | } | ||
| 2120 | } | ||
| 2121 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 66903 times.
|
66903 | while(in.current_line()[0] == '#'); |
| 2122 |
1/2✓ Branch 1 taken 66903 times.
✗ Branch 2 not taken.
|
66903 | in.get_fields(); |
| 2123 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 66902 times.
|
66903 | if(in.nb_fields() != 3) { |
| 2124 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
2 | Logger::err("I/O") |
| 2125 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
|
1 | << "Line " << in.line_number() |
| 2126 | << ": invalid number of fields:" | ||
| 2127 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | << " expected 3 coordinates, got " |
| 2128 |
1/2✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | << in.nb_fields() |
| 2129 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | << std::endl; |
| 2130 | 1 | return false; | |
| 2131 | } | ||
| 2132 | double xyz[3]; | ||
| 2133 |
1/2✓ Branch 1 taken 66902 times.
✗ Branch 2 not taken.
|
66902 | xyz[0] = in.field_as_double(0); |
| 2134 |
2/2✓ Branch 1 taken 66901 times.
✓ Branch 2 taken 1 times.
|
66902 | xyz[1] = in.field_as_double(1); |
| 2135 |
1/2✓ Branch 1 taken 66901 times.
✗ Branch 2 not taken.
|
66901 | xyz[2] = in.field_as_double(2); |
| 2136 |
1/2✓ Branch 1 taken 66901 times.
✗ Branch 2 not taken.
|
66901 | set_mesh_point(M, i, xyz, 3); |
| 2137 | } | ||
| 2138 | |||
| 2139 | 22 | if( | |
| 2140 |
4/6✓ Branch 1 taken 5 times.
✓ Branch 2 taken 17 times.
✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 22 times.
✗ Branch 6 not taken.
|
27 | ioflags.has_element(MESH_FACETS) || |
| 2141 | 5 | ioflags.has_element(MESH_EDGES)) { | |
| 2142 |
6/8✓ Branch 1 taken 131666 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 131666 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 131648 times.
✓ Branch 7 taken 18 times.
✓ Branch 8 taken 131648 times.
✓ Branch 9 taken 18 times.
|
131666 | while(!in.eof() && in.get_line()) { |
| 2143 |
1/2✓ Branch 1 taken 131648 times.
✗ Branch 2 not taken.
|
131648 | in.get_fields(); |
| 2144 | /* if(in.nb_fields() < 4) { | ||
| 2145 | Logger::err("I/O") | ||
| 2146 | << "Line " << in.line_number() | ||
| 2147 | << ": facet line only has " << in.nb_fields() | ||
| 2148 | << " fields (expected 1 count +" | ||
| 2149 | << " at least 3 corner fields)" | ||
| 2150 | << std::endl; | ||
| 2151 | return false; | ||
| 2152 | }*/ | ||
| 2153 |
2/2✓ Branch 1 taken 131647 times.
✓ Branch 2 taken 1 times.
|
131648 | index_t nb_facet_vertices = in.field_as_uint(0); |
| 2154 | |||
| 2155 | // Note: there can be more fields than the number | ||
| 2156 | // of vertices, for instance some OFF files have | ||
| 2157 | // a RGB color for each facet stored right after | ||
| 2158 | // the vertices indices (we ignore it, thus the | ||
| 2159 | // test here is '<' instead of '!='). | ||
| 2160 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 131646 times.
|
131647 | if(in.nb_fields() < nb_facet_vertices + 1) { |
| 2161 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
2 | Logger::err("I/O") |
| 2162 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
|
1 | << "Line " << in.line_number() |
| 2163 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
|
1 | << ": facet has " << in.nb_fields() - 1 |
| 2164 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | << " actual vertices (" |
| 2165 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | << nb_facet_vertices << " expected)" |
| 2166 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | << std::endl; |
| 2167 | 1 | return false; | |
| 2168 | } | ||
| 2169 | |||
| 2170 |
1/2✓ Branch 0 taken 131646 times.
✗ Branch 1 not taken.
|
131646 | if(nb_facet_vertices >= 3) { |
| 2171 |
1/2✓ Branch 1 taken 131646 times.
✗ Branch 2 not taken.
|
131646 | index_t f = M.facets.create_polygon(nb_facet_vertices); |
| 2172 | |||
| 2173 |
2/2✓ Branch 0 taken 394934 times.
✓ Branch 1 taken 131644 times.
|
526578 | for(index_t j = 0; j < nb_facet_vertices; j++) { |
| 2174 |
2/2✓ Branch 1 taken 394933 times.
✓ Branch 2 taken 1 times.
|
394934 | index_t vertex_index = in.field_as_uint(j + 1); |
| 2175 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 394932 times.
|
394933 | if(vertex_index >= M.vertices.nb()) { |
| 2176 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
2 | Logger::err("I/O") |
| 2177 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
|
1 | << "Line " << in.line_number() |
| 2178 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | << ": facet corner #" << j |
| 2179 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | << " references an invalid vertex: " |
| 2180 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | << vertex_index |
| 2181 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | << std::endl; |
| 2182 | 1 | return false; | |
| 2183 | } | ||
| 2184 |
1/2✓ Branch 1 taken 394932 times.
✗ Branch 2 not taken.
|
394932 | M.facets.set_vertex(f, j, vertex_index); |
| 2185 | } | ||
| 2186 | ✗ | } else if(nb_facet_vertices == 2) { | |
| 2187 | ✗ | index_t vertex_index0=in.field_as_uint(1); | |
| 2188 | ✗ | index_t vertex_index1=in.field_as_uint(2); | |
| 2189 | |||
| 2190 | ✗ | if( | |
| 2191 | ✗ | vertex_index0 >= M.vertices.nb() || | |
| 2192 | ✗ | vertex_index1 >= M.vertices.nb() | |
| 2193 | ) { | ||
| 2194 | ✗ | Logger::err("I/O") | |
| 2195 | ✗ | << "Line " << in.line_number() | |
| 2196 | << ": edge" | ||
| 2197 | ✗ | << " references an invalid vertex: " | |
| 2198 | ✗ | << vertex_index0 <<" or "<<vertex_index1 | |
| 2199 | ✗ | << std::endl; | |
| 2200 | ✗ | return false; } | |
| 2201 | ✗ | M.edges.create_edge(vertex_index0, vertex_index1); | |
| 2202 | } | ||
| 2203 | } | ||
| 2204 | } | ||
| 2205 | 18 | return true; | |
| 2206 | 24 | } | |
| 2207 | |||
| 2208 | /** | ||
| 2209 | * \brief Saves a mesh into a file in OFF format. | ||
| 2210 | * \param[in] M The mesh to save | ||
| 2211 | * \param[in] filename name of the file | ||
| 2212 | * \param[in] ioflags specifies which attributes and elements | ||
| 2213 | * should be saved | ||
| 2214 | * \return true on success, false otherwise | ||
| 2215 | */ | ||
| 2216 | 1 | bool save( | |
| 2217 | const Mesh& M, const std::string& filename, | ||
| 2218 | const MeshIOFlags& ioflags | ||
| 2219 | ) override { | ||
| 2220 |
1/2✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | std::ofstream output(filename.c_str()); |
| 2221 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
|
1 | if(!output) { |
| 2222 | ✗ | return false; | |
| 2223 | } | ||
| 2224 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | output << "OFF" << std::endl; |
| 2225 | |||
| 2226 | /*output << M.vertices.nb() << " " | ||
| 2227 | << M.facets.nb() << " " | ||
| 2228 | << M.facet_corners.nb() / 2 | ||
| 2229 | << std::endl;*/ | ||
| 2230 | |||
| 2231 |
2/4✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
|
1 | output << M.vertices.nb() << " " |
| 2232 |
2/4✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
|
1 | << M.facets.nb() << " " |
| 2233 |
1/2✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | << M.edges.nb() |
| 2234 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | << std::endl; |
| 2235 | |||
| 2236 | // Output Vertices | ||
| 2237 |
2/2✓ Branch 1 taken 12 times.
✓ Branch 2 taken 1 times.
|
13 | for(index_t v = 0; v < M.vertices.nb(); ++v) { |
| 2238 | double xyz[3]; | ||
| 2239 |
1/2✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
|
12 | get_mesh_point(M, v, xyz, 3); |
| 2240 |
6/12✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 12 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 12 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 12 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 12 times.
✗ Branch 17 not taken.
|
12 | output << xyz[0] << " " << xyz[1] << " " << xyz[2] << std::endl; |
| 2241 | } | ||
| 2242 | |||
| 2243 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | if(ioflags.has_element(MESH_FACETS)) { |
| 2244 | // Output facets | ||
| 2245 |
2/2✓ Branch 1 taken 20 times.
✓ Branch 2 taken 1 times.
|
21 | for(index_t f = 0; f < M.facets.nb(); ++f) { |
| 2246 |
3/6✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 20 times.
✗ Branch 8 not taken.
|
20 | output << M.facets.nb_vertices(f) << " "; |
| 2247 | 60 | for( | |
| 2248 |
1/2✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
|
20 | index_t c = M.facets.corners_begin(f); |
| 2249 |
3/4✓ Branch 1 taken 80 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 60 times.
✓ Branch 4 taken 20 times.
|
80 | c < M.facets.corners_end(f); ++c |
| 2250 | ) { | ||
| 2251 |
3/6✓ Branch 1 taken 60 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 60 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 60 times.
✗ Branch 8 not taken.
|
60 | output << M.facet_corners.vertex(c) << " "; |
| 2252 | } | ||
| 2253 |
1/2✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
|
20 | output << std::endl; |
| 2254 | } | ||
| 2255 | } | ||
| 2256 | |||
| 2257 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | if(ioflags.has_element(MESH_EDGES)) { |
| 2258 | // Output edges | ||
| 2259 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | for(index_t e = 0; e < M.edges.nb(); ++e) |
| 2260 | { | ||
| 2261 | ✗ | output << "2 " << M.edges.vertex(e, 0) | |
| 2262 | ✗ | << " " << M.edges.vertex(e, 1) | |
| 2263 | ✗ | << std::endl; | |
| 2264 | } | ||
| 2265 | } | ||
| 2266 | 1 | return true; | |
| 2267 | 1 | } | |
| 2268 | }; | ||
| 2269 | |||
| 2270 | /************************************************************************/ | ||
| 2271 | |||
| 2272 | /** | ||
| 2273 | * \brief IO handler for the STL file format (ascii and binary) | ||
| 2274 | * \see http://en.wikipedia.org/wiki/STL_(file_format) | ||
| 2275 | */ | ||
| 2276 | class GEOGRAM_API STLIOHandler : public MeshIOHandler { | ||
| 2277 | public: | ||
| 2278 | /** | ||
| 2279 | * \brief Loads a mesh from a file in STL format (ascii version). | ||
| 2280 | * \param[in] filename name of the file | ||
| 2281 | * \param[out] M the loaded mesh | ||
| 2282 | * \param[in] ioflags specifies which attributes and elements | ||
| 2283 | * should be read | ||
| 2284 | * \return true on success, false otherwise | ||
| 2285 | */ | ||
| 2286 | 3 | bool load_ascii( | |
| 2287 | const std::string& filename, Mesh& M, | ||
| 2288 | const MeshIOFlags& ioflags | ||
| 2289 | ) { | ||
| 2290 | |||
| 2291 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | LineInput in(filename); |
| 2292 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
|
3 | if(!in.OK()) { |
| 2293 | ✗ | return false; | |
| 2294 | } | ||
| 2295 | |||
| 2296 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | bind_attributes(M, ioflags, true); |
| 2297 | |||
| 2298 | 3 | index_t current_chart = 0; | |
| 2299 | 3 | bool facet_opened = false; | |
| 2300 | 3 | vector<index_t> facet_vertices; | |
| 2301 | |||
| 2302 |
6/8✓ Branch 1 taken 452 times.
✓ Branch 2 taken 3 times.
✓ Branch 4 taken 452 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 452 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 452 times.
✓ Branch 9 taken 3 times.
|
455 | while(!in.eof() && in.get_line()) { |
| 2303 |
1/2✓ Branch 1 taken 452 times.
✗ Branch 2 not taken.
|
452 | in.get_fields(); |
| 2304 |
3/4✓ Branch 1 taken 452 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 64 times.
✓ Branch 4 taken 388 times.
|
452 | if(in.field_matches(0, "outer")) { |
| 2305 |
1/2✓ Branch 1 taken 64 times.
✗ Branch 2 not taken.
|
64 | facet_vertices.resize(0); |
| 2306 | 64 | facet_opened = true; | |
| 2307 |
3/4✓ Branch 1 taken 388 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 64 times.
✓ Branch 4 taken 324 times.
|
388 | } else if(in.field_matches(0, "endloop")) { |
| 2308 | 64 | facet_opened = false; | |
| 2309 |
1/2✓ Branch 1 taken 64 times.
✗ Branch 2 not taken.
|
64 | if(ioflags.has_element(MESH_FACETS)) { |
| 2310 |
1/2✓ Branch 2 taken 64 times.
✗ Branch 3 not taken.
|
64 | index_t f = M.facets.create_polygon( |
| 2311 | facet_vertices.size() | ||
| 2312 | ); | ||
| 2313 |
2/2✓ Branch 1 taken 192 times.
✓ Branch 2 taken 64 times.
|
256 | for(index_t lv=0; lv<facet_vertices.size(); ++lv) { |
| 2314 |
2/4✓ Branch 1 taken 192 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 192 times.
✗ Branch 5 not taken.
|
192 | M.facets.set_vertex(f,lv,facet_vertices[lv]); |
| 2315 | } | ||
| 2316 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 64 times.
|
64 | if(facet_region_.is_bound()) { |
| 2317 | ✗ | facet_region_[f] = index_t(current_chart); | |
| 2318 | } | ||
| 2319 | } | ||
| 2320 |
3/4✓ Branch 1 taken 324 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 192 times.
✓ Branch 4 taken 132 times.
|
324 | } else if(in.field_matches(0, "vertex")) { |
| 2321 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 192 times.
|
192 | if(in.nb_fields() < 4) { |
| 2322 | ✗ | Logger::err("I/O") | |
| 2323 | ✗ | << "Line " << in.line_number() | |
| 2324 | ✗ | << ": vertex line has " << in.nb_fields() - 1 | |
| 2325 | ✗ | << " fields (at least 3 required)" | |
| 2326 | ✗ | << std::endl; | |
| 2327 | ✗ | unbind_attributes(); | |
| 2328 | ✗ | return false; | |
| 2329 | } | ||
| 2330 | double xyz[3]; | ||
| 2331 |
1/2✓ Branch 1 taken 192 times.
✗ Branch 2 not taken.
|
192 | xyz[0] = in.field_as_double(1); |
| 2332 |
1/2✓ Branch 1 taken 192 times.
✗ Branch 2 not taken.
|
192 | xyz[1] = in.field_as_double(2); |
| 2333 |
1/2✓ Branch 1 taken 192 times.
✗ Branch 2 not taken.
|
192 | xyz[2] = in.field_as_double(3); |
| 2334 |
1/2✓ Branch 1 taken 192 times.
✗ Branch 2 not taken.
|
192 | index_t v = M.vertices.create_vertex(); |
| 2335 |
1/2✓ Branch 1 taken 192 times.
✗ Branch 2 not taken.
|
192 | set_mesh_point(M, v, xyz, 3); |
| 2336 |
1/2✓ Branch 1 taken 192 times.
✗ Branch 2 not taken.
|
192 | facet_vertices.push_back(v); |
| 2337 |
3/4✓ Branch 1 taken 132 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 131 times.
|
132 | } else if(in.field_matches(0, "solid")) { |
| 2338 | 1 | current_chart++; | |
| 2339 | } | ||
| 2340 | } | ||
| 2341 | |||
| 2342 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if(facet_opened) { |
| 2343 | ✗ | Logger::err("I/O") | |
| 2344 | ✗ | << "Line " << in.line_number() | |
| 2345 | ✗ | << ": current facet is not closed" | |
| 2346 | ✗ | << std::endl; | |
| 2347 | ✗ | unbind_attributes(); | |
| 2348 | ✗ | return false; | |
| 2349 | } | ||
| 2350 | |||
| 2351 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | unbind_attributes(); |
| 2352 | |||
| 2353 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 times.
|
3 | if(M.facets.nb() == 0) { |
| 2354 |
2/4✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
4 | Logger::err("I/O") |
| 2355 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | << "STL file does not contain any facet" |
| 2356 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | << std::endl; |
| 2357 | 2 | return false; | |
| 2358 | } | ||
| 2359 | |||
| 2360 | 1 | return true; | |
| 2361 | 3 | } | |
| 2362 | |||
| 2363 | /** | ||
| 2364 | * \brief Loads a mesh from a file in STL format (binary version). | ||
| 2365 | * \param[in] filename name of the file | ||
| 2366 | * \param[out] M the loaded mesh | ||
| 2367 | * \param[in] ioflags specifies which attributes and elements | ||
| 2368 | * should be read | ||
| 2369 | * \return true on success, false otherwise | ||
| 2370 | */ | ||
| 2371 | 25 | bool load_binary( | |
| 2372 | const std::string& filename, | ||
| 2373 | Mesh& M, const MeshIOFlags& ioflags | ||
| 2374 | ) { | ||
| 2375 |
1/2✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
|
25 | BinaryInputStream in(filename, BinaryStream::GEO_LITTLE_ENDIAN); |
| 2376 | char header[80]; | ||
| 2377 |
1/2✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
|
25 | in.read_opaque_data(header, 80); |
| 2378 |
2/4✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 25 times.
|
25 | if(!in.OK()) { |
| 2379 | ✗ | throw "failed to read header"; | |
| 2380 | } | ||
| 2381 | Numeric::uint32 nb_triangles; | ||
| 2382 |
1/2✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
|
25 | in >> nb_triangles; |
| 2383 |
2/4✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 25 times.
|
25 | if(!in.OK()) { |
| 2384 | ✗ | throw "failed to read number of triangles"; | |
| 2385 | } | ||
| 2386 | |||
| 2387 |
1/2✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
|
25 | bind_attributes(M, ioflags, true); |
| 2388 | |||
| 2389 |
1/2✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
|
25 | M.vertices.create_vertices(nb_triangles*3); |
| 2390 |
1/2✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
|
25 | if(ioflags.has_element(MESH_FACETS)) { |
| 2391 |
1/2✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
|
25 | M.facets.create_triangles(nb_triangles); |
| 2392 | } | ||
| 2393 | |||
| 2394 |
2/2✓ Branch 0 taken 18502 times.
✓ Branch 1 taken 25 times.
|
18527 | for(index_t t = 0; t < nb_triangles; t++) { |
| 2395 | Numeric::float32 N[3]; | ||
| 2396 | Numeric::float32 XYZ[9]; | ||
| 2397 |
3/6✓ Branch 1 taken 18502 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 18502 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 18502 times.
✗ Branch 8 not taken.
|
18502 | in >> N[0] >> N[1] >> N[2]; |
| 2398 |
2/2✓ Branch 0 taken 166518 times.
✓ Branch 1 taken 18502 times.
|
185020 | for(index_t i = 0; i < 9; i++) { |
| 2399 |
1/2✓ Branch 1 taken 166518 times.
✗ Branch 2 not taken.
|
166518 | in >> XYZ[i]; |
| 2400 | } | ||
| 2401 |
2/4✓ Branch 1 taken 18502 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 18502 times.
|
18502 | if(!in.OK()) { |
| 2402 | ✗ | throw "failed to read triangle"; | |
| 2403 | } | ||
| 2404 | Numeric::uint16 attrib; | ||
| 2405 |
1/2✓ Branch 1 taken 18502 times.
✗ Branch 2 not taken.
|
18502 | in >> attrib; |
| 2406 | |||
| 2407 |
1/2✓ Branch 1 taken 18502 times.
✗ Branch 2 not taken.
|
18502 | set_mesh_point(M, 3*t, XYZ, 3); |
| 2408 |
1/2✓ Branch 1 taken 18502 times.
✗ Branch 2 not taken.
|
18502 | set_mesh_point(M, 3*t+1, XYZ+3, 3); |
| 2409 |
1/2✓ Branch 1 taken 18502 times.
✗ Branch 2 not taken.
|
18502 | set_mesh_point(M, 3*t+2, XYZ+6, 3); |
| 2410 | |||
| 2411 |
1/2✓ Branch 1 taken 18502 times.
✗ Branch 2 not taken.
|
18502 | if(ioflags.has_element(MESH_FACETS)) { |
| 2412 |
1/2✓ Branch 1 taken 18502 times.
✗ Branch 2 not taken.
|
18502 | M.facets.set_vertex(t, 0, 3*t); |
| 2413 |
1/2✓ Branch 1 taken 18502 times.
✗ Branch 2 not taken.
|
18502 | M.facets.set_vertex(t, 1, 3*t+1); |
| 2414 |
1/2✓ Branch 1 taken 18502 times.
✗ Branch 2 not taken.
|
18502 | M.facets.set_vertex(t, 2, 3*t+2); |
| 2415 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 18502 times.
|
18502 | if(facet_region_.is_bound()) { |
| 2416 | ✗ | facet_region_[t] = index_t(attrib); | |
| 2417 | } | ||
| 2418 | } | ||
| 2419 | } | ||
| 2420 |
1/2✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
|
25 | unbind_attributes(); |
| 2421 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 25 times.
|
25 | if(M.facets.nb() != nb_triangles) { |
| 2422 | ✗ | Logger::err("I/O") | |
| 2423 | << "STL file does not have " | ||
| 2424 | ✗ | << "the required number of triangles" | |
| 2425 | ✗ | << std::endl; | |
| 2426 | |||
| 2427 | ✗ | return false; | |
| 2428 | } | ||
| 2429 | |||
| 2430 | 25 | return true; | |
| 2431 | 25 | } | |
| 2432 | |||
| 2433 | /** | ||
| 2434 | * \brief Loads a mesh from a file in STL format. | ||
| 2435 | * \details Supports both ascii and binary STL. | ||
| 2436 | * \param[in] filename name of the file | ||
| 2437 | * \param[out] M the loaded mesh | ||
| 2438 | * \param[in] ioflags specifies which attributes and | ||
| 2439 | * elements should be read | ||
| 2440 | * \return true on success, false otherwise | ||
| 2441 | */ | ||
| 2442 | 28 | bool load( | |
| 2443 | const std::string& filename, Mesh& M, | ||
| 2444 | const MeshIOFlags& ioflags | ||
| 2445 | ) override { | ||
| 2446 |
1/2✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
|
28 | FILE* F = fopen(filename.c_str(), "rb"); |
| 2447 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
|
28 | if(F == nullptr) { |
| 2448 | ✗ | return false; | |
| 2449 | } | ||
| 2450 | |||
| 2451 | // The safe way of checking whether an STL file is | ||
| 2452 | // binary is to check whether the size of the file | ||
| 2453 | // matches the size deduced from the number of triangles | ||
| 2454 | // (many binary STL files start with SOLID although it | ||
| 2455 | // is supposed to be only for ASCII STL files) | ||
| 2456 | 28 | fseek(F, 80, SEEK_SET); | |
| 2457 | Numeric::uint32 nb_triangles; | ||
| 2458 |
2/4✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 28 times.
|
28 | if(fread(&nb_triangles, sizeof(nb_triangles), 1, F) != 1) { |
| 2459 | ✗ | Logger::err("I/O") | |
| 2460 | ✗ | << "Cannot deduce the format of STL file" | |
| 2461 | ✗ | << std::endl; | |
| 2462 | ✗ | fclose(F); | |
| 2463 | ✗ | return false; | |
| 2464 | } | ||
| 2465 | 28 | fseek(F, 0, SEEK_END); | |
| 2466 |
1/2✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
|
28 | long file_size = ftell(F); |
| 2467 |
1/2✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
|
28 | fclose(F); |
| 2468 | bool result; | ||
| 2469 |
2/2✓ Branch 0 taken 25 times.
✓ Branch 1 taken 3 times.
|
28 | if(file_size == long(nb_triangles * 50 + 84)) { |
| 2470 |
1/2✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
|
25 | result = load_binary(filename, M, ioflags); |
| 2471 | } else { | ||
| 2472 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | result = load_ascii(filename, M, ioflags); |
| 2473 | } | ||
| 2474 | // STL files have isolated triangles, in general | ||
| 2475 | // the user wants to merge duplicated vertices and connect | ||
| 2476 | // all the triangles, so let's do that. | ||
| 2477 |
2/2✓ Branch 0 taken 26 times.
✓ Branch 1 taken 2 times.
|
28 | if(result) { |
| 2478 |
1/2✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
|
26 | bool fp32 = M.vertices.single_precision(); |
| 2479 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
|
26 | if(fp32) { |
| 2480 | ✗ | M.vertices.set_double_precision(); | |
| 2481 | } | ||
| 2482 |
1/2✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
|
26 | mesh_repair( |
| 2483 | M, | ||
| 2484 | GEO::MeshRepairMode( | ||
| 2485 | GEO::MESH_REPAIR_COLOCATE | GEO::MESH_REPAIR_DUP_F | ||
| 2486 | ), | ||
| 2487 | 0.0 | ||
| 2488 | ); | ||
| 2489 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
|
26 | if(fp32) { |
| 2490 | ✗ | M.vertices.set_single_precision(); | |
| 2491 | } | ||
| 2492 | } | ||
| 2493 | 28 | return result; | |
| 2494 | } | ||
| 2495 | |||
| 2496 | /** | ||
| 2497 | * \brief Writes a point to a binary stream. | ||
| 2498 | * \param[in] out the binary stream | ||
| 2499 | * \param[in] V the vector to write | ||
| 2500 | */ | ||
| 2501 | ✗ | inline void write_stl_vector(BinaryOutputStream& out, const vec3& V) { | |
| 2502 | ✗ | out << Numeric::float32(V.x); | |
| 2503 | ✗ | out << Numeric::float32(V.y); | |
| 2504 | ✗ | out << Numeric::float32(V.z); | |
| 2505 | ✗ | } | |
| 2506 | |||
| 2507 | /** | ||
| 2508 | * \brief Saves a mesh into a file in STL format. | ||
| 2509 | * \param[in] M The mesh to save | ||
| 2510 | * \param[in] filename name of the file | ||
| 2511 | * \param[in] ioflags specifies which attributes | ||
| 2512 | * and elements should be saved | ||
| 2513 | * \return true on success, false otherwise | ||
| 2514 | */ | ||
| 2515 | ✗ | bool save( | |
| 2516 | const Mesh& M, const std::string& filename, | ||
| 2517 | const MeshIOFlags& ioflags | ||
| 2518 | ) override { | ||
| 2519 | ✗ | bool result = true; | |
| 2520 | ✗ | if(CmdLine::get_arg_bool("sys:ascii")) { | |
| 2521 | ✗ | result = save_ascii(M, filename, ioflags); | |
| 2522 | } else { | ||
| 2523 | ✗ | result = save_binary(M, filename, ioflags); | |
| 2524 | } | ||
| 2525 | ✗ | return result; | |
| 2526 | } | ||
| 2527 | |||
| 2528 | /** | ||
| 2529 | * \brief Saves a mesh into a file in STL ASCII format. | ||
| 2530 | * \param[in] M The mesh to save | ||
| 2531 | * \param[in] filename name of the file | ||
| 2532 | * \param[in] ioflags specifies which attributes | ||
| 2533 | * and elements should be saved | ||
| 2534 | * \return true on success, false otherwise | ||
| 2535 | */ | ||
| 2536 | ✗ | bool save_ascii( | |
| 2537 | const Mesh& M, const std::string& filename, | ||
| 2538 | const MeshIOFlags& ioflags | ||
| 2539 | ) { | ||
| 2540 | ✗ | geo_argused(ioflags); | |
| 2541 | ✗ | std::ofstream out(filename.c_str()); | |
| 2542 | ✗ | if(!out) { | |
| 2543 | ✗ | return false; | |
| 2544 | } | ||
| 2545 | ✗ | out << "solid geogram" << std::endl; | |
| 2546 | ✗ | for(index_t f = 0; f < M.facets.nb(); ++f) { | |
| 2547 | ✗ | index_t c1 = M.facets.corners_begin(f); | |
| 2548 | ✗ | vec3 p1; | |
| 2549 | ✗ | get_mesh_point(M, M.facet_corners.vertex(c1), p1.data(), 3); | |
| 2550 | ✗ | for(index_t c2 = M.facets.corners_begin(f) + 1; | |
| 2551 | ✗ | c2 + 1 < M.facets.corners_end(f); ++c2 | |
| 2552 | ) { | ||
| 2553 | ✗ | vec3 p2; | |
| 2554 | ✗ | get_mesh_point( | |
| 2555 | M, M.facet_corners.vertex(c2), p2.data(), 3 | ||
| 2556 | ); | ||
| 2557 | ✗ | vec3 p3; | |
| 2558 | ✗ | get_mesh_point( | |
| 2559 | M, M.facet_corners.vertex(c2+1), p3.data(), 3 | ||
| 2560 | ); | ||
| 2561 | |||
| 2562 | // Seriously, this ASCII STL format is soooo verbose !!! | ||
| 2563 | // Crazy... | ||
| 2564 | ✗ | out << "facet normal " << normalize(cross(p2-p1,p3-p1)) | |
| 2565 | ✗ | << std::endl; | |
| 2566 | ✗ | out << "outer loop" << std::endl; | |
| 2567 | ✗ | out << "vertex " << p1 << std::endl; | |
| 2568 | ✗ | out << "vertex " << p2 << std::endl; | |
| 2569 | ✗ | out << "vertex " << p3 << std::endl; | |
| 2570 | ✗ | out << "endloop" << std::endl; | |
| 2571 | ✗ | out << "endfacet" << std::endl; | |
| 2572 | } | ||
| 2573 | } | ||
| 2574 | ✗ | out << "endsolid" << std::endl; | |
| 2575 | ✗ | return true; | |
| 2576 | ✗ | } | |
| 2577 | |||
| 2578 | /** | ||
| 2579 | * \brief Saves a mesh into a file in STL binary format. | ||
| 2580 | * \param[in] M The mesh to save | ||
| 2581 | * \param[in] filename name of the file | ||
| 2582 | * \param[in] ioflags specifies which attributes | ||
| 2583 | * and elements should be saved | ||
| 2584 | * \return true on success, false otherwise | ||
| 2585 | */ | ||
| 2586 | ✗ | bool save_binary( | |
| 2587 | const Mesh& M, const std::string& filename, | ||
| 2588 | const MeshIOFlags& ioflags | ||
| 2589 | ) { | ||
| 2590 | |||
| 2591 | ✗ | bind_attributes(M, ioflags, false); | |
| 2592 | |||
| 2593 | ✗ | BinaryOutputStream out(filename, BinaryStream::GEO_LITTLE_ENDIAN); | |
| 2594 | char header[80]; | ||
| 2595 | ✗ | Memory::clear(header, 80); | |
| 2596 | ✗ | strcpy(header, "generated with GEOGRAM"); | |
| 2597 | ✗ | out.write_opaque_data(header, 80); | |
| 2598 | ✗ | Numeric::uint32 nb_triangles = 0; | |
| 2599 | ✗ | for(index_t f = 0; f < M.facets.nb(); ++f) { | |
| 2600 | ✗ | nb_triangles += Numeric::uint32((M.facets.nb_vertices(f) - 2)); | |
| 2601 | } | ||
| 2602 | ✗ | out << nb_triangles; | |
| 2603 | ✗ | for(index_t f = 0; f < M.facets.nb(); ++f) { | |
| 2604 | ✗ | index_t c1 = M.facets.corners_begin(f); | |
| 2605 | ✗ | vec3 p1; | |
| 2606 | ✗ | get_mesh_point(M, M.facet_corners.vertex(c1), p1.data(), 3); | |
| 2607 | ✗ | for(index_t c2 = M.facets.corners_begin(f) + 1; | |
| 2608 | ✗ | c2 + 1 < M.facets.corners_end(f); ++c2 | |
| 2609 | ) { | ||
| 2610 | ✗ | vec3 p2; | |
| 2611 | ✗ | get_mesh_point( | |
| 2612 | M, M.facet_corners.vertex(c2), p2.data(), 3 | ||
| 2613 | ); | ||
| 2614 | ✗ | vec3 p3; | |
| 2615 | ✗ | get_mesh_point( | |
| 2616 | M, M.facet_corners.vertex(c2+1), p3.data(), 3 | ||
| 2617 | ); | ||
| 2618 | |||
| 2619 | Numeric::uint16 attribute = Numeric::uint16( | ||
| 2620 | ✗ | facet_region_.is_bound() ? | |
| 2621 | ✗ | facet_region_[f] : 0 | |
| 2622 | ✗ | ); | |
| 2623 | |||
| 2624 | ✗ | write_stl_vector(out, normalize(cross(p2-p1,p3-p1))); | |
| 2625 | ✗ | write_stl_vector(out, p1); | |
| 2626 | ✗ | write_stl_vector(out, p2); | |
| 2627 | ✗ | write_stl_vector(out, p3); | |
| 2628 | |||
| 2629 | ✗ | out << attribute; | |
| 2630 | } | ||
| 2631 | } | ||
| 2632 | ✗ | unbind_attributes(); | |
| 2633 | ✗ | return true; | |
| 2634 | ✗ | } | |
| 2635 | }; | ||
| 2636 | |||
| 2637 | /************************************************************************/ | ||
| 2638 | |||
| 2639 | |||
| 2640 | /** | ||
| 2641 | * \brief IO handler for the XYZ file format | ||
| 2642 | * \details Currtently only loading is supported | ||
| 2643 | */ | ||
| 2644 | class GEOGRAM_API XYZIOHandler : public MeshIOHandler { | ||
| 2645 | public: | ||
| 2646 | /** | ||
| 2647 | * \brief Loads a pointset from a file in XYZ format. | ||
| 2648 | * \param[in] filename name of the file | ||
| 2649 | * \param[out] M the mesh where to store the points | ||
| 2650 | * \param[in] ioflags specifies which attributes and | ||
| 2651 | * elements should be read | ||
| 2652 | * \return true on success, false otherwise | ||
| 2653 | */ | ||
| 2654 | ✗ | bool load( | |
| 2655 | const std::string& filename, Mesh& M, | ||
| 2656 | const MeshIOFlags& ioflags | ||
| 2657 | ) override { | ||
| 2658 | ✗ | geo_argused(ioflags); | |
| 2659 | ✗ | index_t nb_vertices = get_nb_vertices(filename); | |
| 2660 | ✗ | if(nb_vertices == NO_INDEX) { | |
| 2661 | ✗ | return false; | |
| 2662 | } | ||
| 2663 | |||
| 2664 | ✗ | M.vertices.create_vertices(nb_vertices); | |
| 2665 | |||
| 2666 | ✗ | LineInput in(filename); | |
| 2667 | ✗ | if(!in.OK()) { | |
| 2668 | ✗ | return false; | |
| 2669 | } | ||
| 2670 | ✗ | Attribute<double> normal; | |
| 2671 | ✗ | index_t cur_v = 0; | |
| 2672 | ✗ | while(!in.eof() && in.get_line()) { | |
| 2673 | ✗ | in.get_fields(); | |
| 2674 | ✗ | switch(in.nb_fields()) { | |
| 2675 | ✗ | case 1: | |
| 2676 | ✗ | break; | |
| 2677 | ✗ | case 2: | |
| 2678 | case 3: | ||
| 2679 | case 4: | ||
| 2680 | case 6: | ||
| 2681 | { | ||
| 2682 | double xyz[3]; | ||
| 2683 | ✗ | xyz[0] = in.field_as_double(0); | |
| 2684 | ✗ | xyz[1] = in.field_as_double(1); | |
| 2685 | ✗ | xyz[2] = | |
| 2686 | ✗ | (in.nb_fields() >= 3) ? in.field_as_double(2) : 0.0; | |
| 2687 | // Not all xyz files have the number of vertices | ||
| 2688 | // specified on the first line. If it is unknown, | ||
| 2689 | // then vertices are created dynamically. | ||
| 2690 | ✗ | if(cur_v+1 >= M.vertices.nb()) { | |
| 2691 | ✗ | M.vertices.create_vertices(cur_v+1-M.vertices.nb()); | |
| 2692 | } | ||
| 2693 | ✗ | set_mesh_point(M,cur_v,xyz,3); | |
| 2694 | |||
| 2695 | ✗ | if(in.nb_fields() == 6) { | |
| 2696 | ✗ | if(!normal.is_bound()) { | |
| 2697 | ✗ | normal.create_vector_attribute( | |
| 2698 | ✗ | M.vertices.attributes(), "normal", 3 | |
| 2699 | ); | ||
| 2700 | } | ||
| 2701 | ✗ | normal[3*cur_v] = in.field_as_double(3); | |
| 2702 | ✗ | normal[3*cur_v+1] = in.field_as_double(4); | |
| 2703 | ✗ | normal[3*cur_v+2] = in.field_as_double(5); | |
| 2704 | } | ||
| 2705 | |||
| 2706 | ✗ | ++cur_v; | |
| 2707 | } | ||
| 2708 | ✗ | break; | |
| 2709 | ✗ | default: | |
| 2710 | ✗ | Logger::err("I/O") | |
| 2711 | ✗ | << "Line " << in.line_number() | |
| 2712 | ✗ | << ": wrong number of fields" | |
| 2713 | ✗ | << std::endl; | |
| 2714 | ✗ | return false; | |
| 2715 | } | ||
| 2716 | } | ||
| 2717 | ✗ | return true; | |
| 2718 | ✗ | } | |
| 2719 | |||
| 2720 | ✗ | bool save( | |
| 2721 | const Mesh& M, const std::string& filename, | ||
| 2722 | const MeshIOFlags& ioflags | ||
| 2723 | ) override { | ||
| 2724 | ✗ | geo_argused(ioflags); | |
| 2725 | |||
| 2726 | ✗ | if(M.vertices.dimension() < 3) { | |
| 2727 | ✗ | Logger::err("I/O") | |
| 2728 | ✗ | << "XYZ format unsupported for dim < 3" | |
| 2729 | ✗ | << std::endl; | |
| 2730 | ✗ | return false; | |
| 2731 | } | ||
| 2732 | |||
| 2733 | ✗ | std::ofstream out(filename.c_str()); | |
| 2734 | ✗ | if(!out) { | |
| 2735 | ✗ | Logger::err("I/O") | |
| 2736 | << "Could not create file : " | ||
| 2737 | ✗ | << filename | |
| 2738 | ✗ | << std::endl; | |
| 2739 | ✗ | return false; | |
| 2740 | } | ||
| 2741 | |||
| 2742 | ✗ | Attribute<double> normal; | |
| 2743 | ✗ | normal.bind_if_is_defined(M.vertices.attributes(), "normal"); | |
| 2744 | ✗ | if(normal.is_bound() && normal.dimension() != 3) { | |
| 2745 | ✗ | normal.unbind(); | |
| 2746 | } | ||
| 2747 | |||
| 2748 | ✗ | out << M.vertices.nb() << std::endl; | |
| 2749 | |||
| 2750 | ✗ | for(index_t v=0; v<M.vertices.nb(); ++v) { | |
| 2751 | double point[3]; | ||
| 2752 | ✗ | get_mesh_point(M,v,point,3); | |
| 2753 | ✗ | if(normal.is_bound()) { | |
| 2754 | ✗ | out << point[0] << ' ' | |
| 2755 | ✗ | << point[1] << ' ' | |
| 2756 | ✗ | << point[2] << ' ' | |
| 2757 | ✗ | << normal[3*v] << ' ' | |
| 2758 | ✗ | << normal[3*v+1] << ' ' | |
| 2759 | ✗ | << normal[3*v+2] << ' ' | |
| 2760 | ✗ | << std::endl; | |
| 2761 | ✗ | } else if( | |
| 2762 | ✗ | M.vertices.dimension() >= 6 && | |
| 2763 | ✗ | M.vertices.double_precision() | |
| 2764 | ) { | ||
| 2765 | ✗ | const double* p = M.vertices.point_ptr(v); | |
| 2766 | ✗ | out << p[0] << ' ' | |
| 2767 | ✗ | << p[1] << ' ' | |
| 2768 | ✗ | << p[2] << ' ' | |
| 2769 | ✗ | << p[3] << ' ' | |
| 2770 | ✗ | << p[4] << ' ' | |
| 2771 | ✗ | << p[5] << std::endl; | |
| 2772 | } else { | ||
| 2773 | ✗ | out << point[0] << ' ' | |
| 2774 | ✗ | << point[1] << ' ' | |
| 2775 | ✗ | << point[2] << std::endl; | |
| 2776 | } | ||
| 2777 | } | ||
| 2778 | |||
| 2779 | ✗ | return true; | |
| 2780 | ✗ | } | |
| 2781 | |||
| 2782 | protected: | ||
| 2783 | |||
| 2784 | /** | ||
| 2785 | * \brief Gets the number of vertices in the file. | ||
| 2786 | * \details Some xyz files do not have the number of | ||
| 2787 | * points specified in them. For these files, this | ||
| 2788 | * function reads the entire file once and counts the | ||
| 2789 | * points. It is better to do so, because it makes it | ||
| 2790 | * possible to allocate the points once we known the | ||
| 2791 | * required size, instead of growing. | ||
| 2792 | * \param[in] filename the name of the file. | ||
| 2793 | * \return the number of vertices in the file, or | ||
| 2794 | * NO_INDEX if the file could not be opened. | ||
| 2795 | */ | ||
| 2796 | ✗ | index_t get_nb_vertices(const std::string& filename) { | |
| 2797 | ✗ | index_t result = 0; | |
| 2798 | ✗ | LineInput in(filename); | |
| 2799 | ✗ | if(!in.OK()) { | |
| 2800 | ✗ | return NO_INDEX; | |
| 2801 | } | ||
| 2802 | ✗ | while(!in.eof() && in.get_line()) { | |
| 2803 | ✗ | in.get_fields(); | |
| 2804 | ✗ | switch(in.nb_fields()) { | |
| 2805 | ✗ | case 1: | |
| 2806 | ✗ | return in.field_as_uint(0); | |
| 2807 | ✗ | case 2: | |
| 2808 | case 3: | ||
| 2809 | case 4: | ||
| 2810 | case 6: | ||
| 2811 | ✗ | ++result; | |
| 2812 | ✗ | break; | |
| 2813 | ✗ | default: | |
| 2814 | ✗ | Logger::err("I/O") | |
| 2815 | ✗ | << "Line " << in.line_number() | |
| 2816 | ✗ | << ": wrong number of fields" | |
| 2817 | ✗ | << std::endl; | |
| 2818 | ✗ | return NO_INDEX; | |
| 2819 | } | ||
| 2820 | } | ||
| 2821 | ✗ | return result; | |
| 2822 | ✗ | } | |
| 2823 | }; | ||
| 2824 | |||
| 2825 | |||
| 2826 | /************************************************************************/ | ||
| 2827 | |||
| 2828 | /** | ||
| 2829 | * \brief IO handler for the PTS file format | ||
| 2830 | */ | ||
| 2831 | class GEOGRAM_API PTSIOHandler : public MeshIOHandler { | ||
| 2832 | public: | ||
| 2833 | /** | ||
| 2834 | * \brief Loads a pointset from a file in PTS format. | ||
| 2835 | * \param[in] filename name of the file | ||
| 2836 | * \param[out] M the mesh where to store the points | ||
| 2837 | * \param[in] ioflags specifies which attributes and | ||
| 2838 | * elements should be read | ||
| 2839 | * \return true on success, false otherwise | ||
| 2840 | */ | ||
| 2841 | ✗ | bool load( | |
| 2842 | const std::string& filename, Mesh& M, | ||
| 2843 | const MeshIOFlags& ioflags | ||
| 2844 | ) override { | ||
| 2845 | ✗ | geo_argused(ioflags); | |
| 2846 | |||
| 2847 | ✗ | LineInput in(filename); | |
| 2848 | ✗ | if(!in.OK()) { | |
| 2849 | ✗ | return false; | |
| 2850 | } | ||
| 2851 | ✗ | while(!in.eof() && in.get_line()) { | |
| 2852 | ✗ | in.get_fields(); | |
| 2853 | ✗ | if(in.nb_fields() == 4 && in.field_matches(0,"v")) { | |
| 2854 | double xyz[3]; | ||
| 2855 | ✗ | xyz[0] = in.field_as_double(1); | |
| 2856 | ✗ | xyz[1] = in.field_as_double(2); | |
| 2857 | ✗ | xyz[2] = in.field_as_double(3); | |
| 2858 | ✗ | index_t v = M.vertices.create_vertex(); | |
| 2859 | ✗ | set_mesh_point(M,v,xyz,3); | |
| 2860 | } else { | ||
| 2861 | ✗ | Logger::err("I/O") | |
| 2862 | ✗ | << "Line " << in.line_number() | |
| 2863 | ✗ | << ": wrong number of fields" | |
| 2864 | ✗ | << std::endl; | |
| 2865 | ✗ | return false; | |
| 2866 | } | ||
| 2867 | } | ||
| 2868 | ✗ | return true; | |
| 2869 | ✗ | } | |
| 2870 | |||
| 2871 | ✗ | bool save( | |
| 2872 | const Mesh& M, const std::string& filename, | ||
| 2873 | const MeshIOFlags& ioflags | ||
| 2874 | ) override { | ||
| 2875 | ✗ | geo_argused(ioflags); | |
| 2876 | |||
| 2877 | ✗ | std::ofstream out(filename.c_str()); | |
| 2878 | ✗ | if(!out) { | |
| 2879 | ✗ | Logger::err("I/O") | |
| 2880 | << "Could not create file \'" | ||
| 2881 | ✗ | << filename << "\'" << std::endl; | |
| 2882 | ✗ | return false; | |
| 2883 | } | ||
| 2884 | ✗ | if(M.vertices.dimension() != 3) { | |
| 2885 | ✗ | Logger::err("I/O") | |
| 2886 | ✗ | << "invalid dimension for pts file format" | |
| 2887 | ✗ | << std::endl; | |
| 2888 | ✗ | return false; | |
| 2889 | } | ||
| 2890 | |||
| 2891 | ✗ | for(index_t v = 0; v < M.vertices.nb(); ++v) { | |
| 2892 | double p[3]; | ||
| 2893 | ✗ | get_mesh_point(M,v,p,3); | |
| 2894 | ✗ | out << "v "; | |
| 2895 | ✗ | for(index_t c = 0; c < 3; ++c) { | |
| 2896 | ✗ | out << p[c] << ' '; | |
| 2897 | } | ||
| 2898 | ✗ | out << std::endl; | |
| 2899 | } | ||
| 2900 | |||
| 2901 | ✗ | return true; | |
| 2902 | ✗ | } | |
| 2903 | }; | ||
| 2904 | |||
| 2905 | /************************************************************************/ | ||
| 2906 | |||
| 2907 | /** | ||
| 2908 | * \brief IO handler for the TET file format | ||
| 2909 | */ | ||
| 2910 | class GEOGRAM_API TETIOHandler : public MeshIOHandler { | ||
| 2911 | public: | ||
| 2912 | /** | ||
| 2913 | * \brief Creates a TET IO handler. | ||
| 2914 | * \param[in] dimension dimension of the vertices | ||
| 2915 | * (3 for regular 3d mesh) | ||
| 2916 | */ | ||
| 2917 | 4 | TETIOHandler(coord_index_t dimension = 3) : | |
| 2918 | 4 | dimension_(dimension) { | |
| 2919 | 4 | } | |
| 2920 | |||
| 2921 | /** | ||
| 2922 | * \brief Loads a mesh from a file in TET format. | ||
| 2923 | * \details Only tetrahedral cells are supported for now. | ||
| 2924 | * \param[in] filename name of the file | ||
| 2925 | * \param[out] M the loaded mesh | ||
| 2926 | * \param[in] ioflags specifies which attributes and elements | ||
| 2927 | * should be read | ||
| 2928 | * \return true on success, false otherwise | ||
| 2929 | */ | ||
| 2930 | 4 | bool load( | |
| 2931 | const std::string& filename, Mesh& M, | ||
| 2932 | const MeshIOFlags& ioflags | ||
| 2933 | ) override { | ||
| 2934 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | LineInput in(filename); |
| 2935 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
|
4 | if(!in.OK()) { |
| 2936 | ✗ | return false; | |
| 2937 | } | ||
| 2938 |
2/4✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
|
4 | if(!in.get_line()) { |
| 2939 | ✗ | Logger::err("I/O") | |
| 2940 | ✗ | << "Unexpected end of file" | |
| 2941 | ✗ | << std::endl; | |
| 2942 | ✗ | return false; | |
| 2943 | } | ||
| 2944 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | in.get_fields(); |
| 2945 | |||
| 2946 | 4 | index_t nb_vertices = 0; | |
| 2947 | 4 | index_t nb_cells = 0; | |
| 2948 | 4 | bool has_arbitrary_cells = false; | |
| 2949 | |||
| 2950 | 4 | if( | |
| 2951 | 4 | in.nb_fields() == 4 && | |
| 2952 |
2/8✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 4 times.
|
4 | in.field_matches(1, "vertices") && |
| 2953 | ( | ||
| 2954 | ✗ | in.field_matches(3, "tets") || | |
| 2955 | ✗ | in.field_matches(3, "cells") | |
| 2956 | ) | ||
| 2957 | ) { | ||
| 2958 | ✗ | nb_vertices = in.field_as_uint(0); | |
| 2959 | ✗ | nb_cells = in.field_as_uint(2); | |
| 2960 | ✗ | has_arbitrary_cells = in.field_matches(3, "cells"); | |
| 2961 | } else { | ||
| 2962 |
4/8✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 4 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 4 times.
|
4 | if(in.nb_fields() != 2 || !in.field_matches(1, "vertices")) { |
| 2963 | ✗ | Logger::err("I/O") | |
| 2964 | ✗ | << "Line " << in.line_number() | |
| 2965 | ✗ | << " expected <number_of_vertices> vertices" | |
| 2966 | ✗ | << std::endl; | |
| 2967 | ✗ | return false; | |
| 2968 | } | ||
| 2969 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | nb_vertices = in.field_as_uint(0); |
| 2970 | |||
| 2971 |
2/4✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
|
4 | if(!in.get_line()) { |
| 2972 | ✗ | Logger::err("I/O") | |
| 2973 | ✗ | << "Unexpected end of file" | |
| 2974 | ✗ | << std::endl; | |
| 2975 | ✗ | return false; | |
| 2976 | } | ||
| 2977 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | in.get_fields(); |
| 2978 | 4 | if( | |
| 2979 |
2/4✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
|
8 | in.nb_fields() != 2 || ( |
| 2980 |
2/4✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
|
4 | !in.field_matches(1, "tets") && |
| 2981 | ✗ | !in.field_matches(1, "cells") | |
| 2982 | ) | ||
| 2983 | ) { | ||
| 2984 | ✗ | Logger::err("I/O") | |
| 2985 | ✗ | << "Line " << in.line_number() | |
| 2986 | ✗ | << " expected <number_of_tets> tets" | |
| 2987 | ✗ | << std::endl; | |
| 2988 | ✗ | return false; | |
| 2989 | } | ||
| 2990 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | nb_cells = in.field_as_uint(0); |
| 2991 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | has_arbitrary_cells = in.field_matches(1, "cells"); |
| 2992 | } | ||
| 2993 | |||
| 2994 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | M.vertices.set_dimension(dimension_); |
| 2995 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | M.vertices.create_vertices(nb_vertices); |
| 2996 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | vector<double> P(dimension_); |
| 2997 |
2/2✓ Branch 0 taken 500 times.
✓ Branch 1 taken 4 times.
|
504 | for(index_t v = 0; v < nb_vertices; ++v) { |
| 2998 |
2/4✓ Branch 1 taken 500 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 500 times.
|
500 | if(!in.get_line()) { |
| 2999 | ✗ | Logger::err("I/O") | |
| 3000 | ✗ | << "Unexpected end of file" | |
| 3001 | ✗ | << std::endl; | |
| 3002 | ✗ | return false; | |
| 3003 | } | ||
| 3004 |
1/2✓ Branch 1 taken 500 times.
✗ Branch 2 not taken.
|
500 | in.get_fields(); |
| 3005 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 500 times.
|
500 | if(in.nb_fields() != index_t(dimension_)) { |
| 3006 | ✗ | Logger::err("I/O") | |
| 3007 | ✗ | << "Line " << in.line_number() | |
| 3008 | ✗ | << " expected " << dimension_ << " point coordinates" | |
| 3009 | ✗ | << std::endl; | |
| 3010 | } | ||
| 3011 |
2/2✓ Branch 0 taken 4000 times.
✓ Branch 1 taken 500 times.
|
4500 | for(coord_index_t c = 0; c < dimension_; ++c) { |
| 3012 |
2/4✓ Branch 1 taken 4000 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4000 times.
✗ Branch 5 not taken.
|
4000 | P[c] = in.field_as_double(c); |
| 3013 | } | ||
| 3014 |
1/2✓ Branch 2 taken 500 times.
✗ Branch 3 not taken.
|
500 | set_mesh_point(M,v,P.data(),dimension_); |
| 3015 | } | ||
| 3016 | |||
| 3017 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | if(ioflags.has_element(MESH_CELLS)) { |
| 3018 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if(has_arbitrary_cells) { |
| 3019 | ✗ | for(index_t t = 0; t < nb_cells; ++t) { | |
| 3020 | ✗ | if(!in.get_line()) { | |
| 3021 | ✗ | Logger::err("I/O") | |
| 3022 | ✗ | << "Unexpected end of file" | |
| 3023 | ✗ | << std::endl; | |
| 3024 | ✗ | return false; | |
| 3025 | } | ||
| 3026 | ✗ | in.get_fields(); | |
| 3027 | ✗ | if( | |
| 3028 | ✗ | in.nb_fields() >= 2 && | |
| 3029 | ✗ | in.field_matches(0,"#") && in.field_matches(1,"C") | |
| 3030 | ) { | ||
| 3031 | ✗ | if(in.nb_fields() != 6) { | |
| 3032 | ✗ | Logger::err("I/O") | |
| 3033 | ✗ | << "Line " << in.line_number() | |
| 3034 | ✗ | << " expected # C v1 v2 v3 v4" | |
| 3035 | ✗ | << std::endl; | |
| 3036 | ✗ | return false; | |
| 3037 | } | ||
| 3038 | ✗ | M.cells.create_connector( | |
| 3039 | in.field_as_uint(2), | ||
| 3040 | in.field_as_uint(3), | ||
| 3041 | in.field_as_uint(4), | ||
| 3042 | in.field_as_uint(5) | ||
| 3043 | ); | ||
| 3044 | } else { | ||
| 3045 | ✗ | if(in.nb_fields() > 0) { | |
| 3046 | index_t nb_vertices_in_cell = | ||
| 3047 | ✗ | in.field_as_uint(0); | |
| 3048 | ✗ | switch(nb_vertices_in_cell) { | |
| 3049 | ✗ | case 4: { | |
| 3050 | ✗ | M.cells.create_tet( | |
| 3051 | in.field_as_uint(1), | ||
| 3052 | in.field_as_uint(2), | ||
| 3053 | in.field_as_uint(3), | ||
| 3054 | in.field_as_uint(4) | ||
| 3055 | ); | ||
| 3056 | ✗ | } break; | |
| 3057 | ✗ | case 8: { | |
| 3058 | ✗ | M.cells.create_hex( | |
| 3059 | in.field_as_uint(1), | ||
| 3060 | in.field_as_uint(2), | ||
| 3061 | in.field_as_uint(3), | ||
| 3062 | in.field_as_uint(4), | ||
| 3063 | in.field_as_uint(5), | ||
| 3064 | in.field_as_uint(6), | ||
| 3065 | in.field_as_uint(7), | ||
| 3066 | in.field_as_uint(8) | ||
| 3067 | ); | ||
| 3068 | ✗ | } break; | |
| 3069 | ✗ | case 6: { | |
| 3070 | ✗ | M.cells.create_prism( | |
| 3071 | in.field_as_uint(1), | ||
| 3072 | in.field_as_uint(2), | ||
| 3073 | in.field_as_uint(3), | ||
| 3074 | in.field_as_uint(4), | ||
| 3075 | in.field_as_uint(5), | ||
| 3076 | in.field_as_uint(6) | ||
| 3077 | ); | ||
| 3078 | ✗ | } break; | |
| 3079 | ✗ | case 5: { | |
| 3080 | ✗ | M.cells.create_pyramid( | |
| 3081 | in.field_as_uint(1), | ||
| 3082 | in.field_as_uint(2), | ||
| 3083 | in.field_as_uint(3), | ||
| 3084 | in.field_as_uint(4), | ||
| 3085 | in.field_as_uint(5) | ||
| 3086 | ); | ||
| 3087 | ✗ | } break; | |
| 3088 | ✗ | default: { | |
| 3089 | ✗ | Logger::err("I/O") | |
| 3090 | ✗ | << "Line " << in.line_number() | |
| 3091 | ✗ | << " unexpected number of vertices in cell:" | |
| 3092 | ✗ | << nb_vertices_in_cell | |
| 3093 | ✗ | << std::endl; | |
| 3094 | ✗ | return false; | |
| 3095 | } | ||
| 3096 | } | ||
| 3097 | } | ||
| 3098 | } | ||
| 3099 | } | ||
| 3100 | } else { | ||
| 3101 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | M.cells.create_tets(nb_cells); |
| 3102 |
2/2✓ Branch 0 taken 1536 times.
✓ Branch 1 taken 4 times.
|
1540 | for(index_t t = 0; t < nb_cells; ++t) { |
| 3103 |
2/4✓ Branch 1 taken 1536 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1536 times.
|
1536 | if(!in.get_line()) { |
| 3104 | ✗ | Logger::err("I/O") | |
| 3105 | ✗ | << "Unexpected end of file" | |
| 3106 | ✗ | << std::endl; | |
| 3107 | ✗ | return false; | |
| 3108 | } | ||
| 3109 |
1/2✓ Branch 1 taken 1536 times.
✗ Branch 2 not taken.
|
1536 | in.get_fields(); |
| 3110 |
4/8✓ Branch 1 taken 1536 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1536 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1536 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 1536 times.
|
1536 | if(in.nb_fields() != 5 || in.field_as_int(0) != 4) { |
| 3111 | ✗ | Logger::err("I/O") | |
| 3112 | ✗ | << "Line " << in.line_number() | |
| 3113 | ✗ | << " expected 4 v1 v2 v3 v4" | |
| 3114 | ✗ | << std::endl; | |
| 3115 | } else { | ||
| 3116 |
2/2✓ Branch 0 taken 6144 times.
✓ Branch 1 taken 1536 times.
|
7680 | for(index_t i = 0; i < 4; ++i) { |
| 3117 |
1/2✓ Branch 1 taken 6144 times.
✗ Branch 2 not taken.
|
6144 | index_t v = in.field_as_uint(i + 1); |
| 3118 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6144 times.
|
6144 | if(i >= nb_vertices) { |
| 3119 | ✗ | Logger::err("I/O") | |
| 3120 | ✗ | << "Line " << in.line_number() | |
| 3121 | ✗ | << "invalid vertex index" | |
| 3122 | ✗ | << std::endl; | |
| 3123 | ✗ | return false; | |
| 3124 | } | ||
| 3125 |
1/2✓ Branch 1 taken 6144 times.
✗ Branch 2 not taken.
|
6144 | M.cells.set_vertex(t, i, v); |
| 3126 | } | ||
| 3127 | } | ||
| 3128 | } | ||
| 3129 | } | ||
| 3130 | } | ||
| 3131 | 4 | return true; | |
| 3132 | 4 | } | |
| 3133 | |||
| 3134 | /** | ||
| 3135 | * \brief Saves a mesh into a file in TET format. | ||
| 3136 | * \param[in] M The mesh to save | ||
| 3137 | * \param[in] filename name of the file | ||
| 3138 | * \param[in] ioflags specifies which attributes and elements | ||
| 3139 | * should be saved | ||
| 3140 | * \return true on success, false otherwise | ||
| 3141 | */ | ||
| 3142 | ✗ | bool save( | |
| 3143 | const Mesh& M, const std::string& filename, | ||
| 3144 | const MeshIOFlags& ioflags | ||
| 3145 | ) override { | ||
| 3146 | ✗ | geo_argused(ioflags); | |
| 3147 | |||
| 3148 | ✗ | if(M.vertices.dimension() < dimension_) { | |
| 3149 | ✗ | return false; | |
| 3150 | } | ||
| 3151 | ✗ | std::ofstream out(filename.c_str()); | |
| 3152 | ✗ | if(!out) { | |
| 3153 | ✗ | return false; | |
| 3154 | } | ||
| 3155 | ✗ | vector<double> P(dimension_); | |
| 3156 | ✗ | if(M.cells.are_simplices()) { | |
| 3157 | ✗ | out << M.vertices.nb() << " vertices" << std::endl; | |
| 3158 | ✗ | out << M.cells.nb() << " tets" << std::endl; | |
| 3159 | ✗ | for(index_t v = 0; v < M.vertices.nb(); ++v) { | |
| 3160 | ✗ | get_mesh_point(M,v,P.data(),dimension_); | |
| 3161 | ✗ | for(coord_index_t c = 0; c < dimension_; ++c) { | |
| 3162 | ✗ | out << P[c] << " "; | |
| 3163 | } | ||
| 3164 | ✗ | out << std::endl; | |
| 3165 | } | ||
| 3166 | ✗ | for(index_t t = 0; t < M.cells.nb(); ++t) { | |
| 3167 | ✗ | out << "4"; | |
| 3168 | ✗ | for(index_t i = 0; i < 4; ++i) { | |
| 3169 | ✗ | out << " " << M.cells.vertex(t, i); | |
| 3170 | } | ||
| 3171 | ✗ | out << std::endl; | |
| 3172 | } | ||
| 3173 | } else { | ||
| 3174 | ✗ | out << M.vertices.nb() << " vertices" << std::endl; | |
| 3175 | ✗ | out << M.cells.nb() << " cells" << std::endl; | |
| 3176 | ✗ | for(index_t v = 0; v < M.vertices.nb(); ++v) { | |
| 3177 | ✗ | get_mesh_point(M,v,P.data(),dimension_); | |
| 3178 | ✗ | for(coord_index_t c = 0; c < dimension_; ++c) { | |
| 3179 | ✗ | out << P[c] << " "; | |
| 3180 | } | ||
| 3181 | ✗ | out << std::endl; | |
| 3182 | } | ||
| 3183 | ✗ | bool has_connectors = false; | |
| 3184 | ✗ | for(index_t c=0; c<M.cells.nb(); ++c) { | |
| 3185 | ✗ | switch(M.cells.type(c)) { | |
| 3186 | ✗ | case MESH_TET: | |
| 3187 | case MESH_HEX: | ||
| 3188 | case MESH_PRISM: | ||
| 3189 | case MESH_PYRAMID: { | ||
| 3190 | ✗ | out << M.cells.nb_vertices(c) << " "; | |
| 3191 | ✗ | for(index_t lv=0; lv<M.cells.nb_vertices(c); ++lv) { | |
| 3192 | ✗ | out << M.cells.vertex(c,lv) << " "; | |
| 3193 | } | ||
| 3194 | ✗ | out << std::endl; | |
| 3195 | ✗ | } break; | |
| 3196 | ✗ | case MESH_CONNECTOR: { | |
| 3197 | ✗ | has_connectors=true; | |
| 3198 | ✗ | } break; | |
| 3199 | ✗ | case MESH_NB_CELL_TYPES: | |
| 3200 | ✗ | geo_assert_not_reached; | |
| 3201 | } | ||
| 3202 | } | ||
| 3203 | ✗ | if(has_connectors) { | |
| 3204 | ✗ | for(index_t c=0; c<M.cells.nb(); ++c) { | |
| 3205 | ✗ | if(M.cells.type(c) == MESH_CONNECTOR) { | |
| 3206 | out << "# C" | ||
| 3207 | ✗ | << " " << M.cells.vertex(c,0) | |
| 3208 | ✗ | << " " << M.cells.vertex(c,1) | |
| 3209 | ✗ | << " " << M.cells.vertex(c,2) | |
| 3210 | ✗ | << " " << M.cells.vertex(c,3) | |
| 3211 | ✗ | << std::endl; | |
| 3212 | } | ||
| 3213 | } | ||
| 3214 | } | ||
| 3215 | } | ||
| 3216 | ✗ | return true; | |
| 3217 | ✗ | } | |
| 3218 | |||
| 3219 | private: | ||
| 3220 | coord_index_t dimension_; | ||
| 3221 | }; | ||
| 3222 | |||
| 3223 | /************************************************************************/ | ||
| 3224 | |||
| 3225 | /** | ||
| 3226 | * \brief IO handler for the TET6 file format | ||
| 3227 | * \see TETIOHandler | ||
| 3228 | */ | ||
| 3229 | class GEOGRAM_API TET6IOHandler : public TETIOHandler { | ||
| 3230 | public: | ||
| 3231 | ✗ | TET6IOHandler() : TETIOHandler(6) { | |
| 3232 | ✗ | } | |
| 3233 | }; | ||
| 3234 | |||
| 3235 | /** | ||
| 3236 | * \brief IO handler for the TET8 file format | ||
| 3237 | * \see TETIOHandler | ||
| 3238 | */ | ||
| 3239 | class GEOGRAM_API TET8IOHandler : public TETIOHandler { | ||
| 3240 | public: | ||
| 3241 | 4 | TET8IOHandler() : TETIOHandler(8) { | |
| 3242 | 4 | } | |
| 3243 | }; | ||
| 3244 | |||
| 3245 | |||
| 3246 | /************************************************************************/ | ||
| 3247 | |||
| 3248 | /** | ||
| 3249 | * \brief IO handler for the geogram native file format. | ||
| 3250 | */ | ||
| 3251 | class GEOGRAM_API GeogramIOHandler : public MeshIOHandler { | ||
| 3252 | public: | ||
| 3253 | |||
| 3254 | |||
| 3255 | /** | ||
| 3256 | * \brief Loads a mesh from a GeoFile ('.geogram' file format). | ||
| 3257 | * \details | ||
| 3258 | * Loads the contents of the InputGeoFile \p geofile and stores the | ||
| 3259 | * resulting mesh to \p M. This function can be used to load several | ||
| 3260 | * meshes that are stored in the same GeoFile. | ||
| 3261 | * \param[in] in a reference to the InputGeoFile | ||
| 3262 | * \param[out] M the loaded mesh | ||
| 3263 | * \param[in] ioflags specifies which attributes and | ||
| 3264 | * elements should be loaded | ||
| 3265 | * \return true on success, false otherwise. | ||
| 3266 | */ | ||
| 3267 | 3 | virtual bool load( | |
| 3268 | InputGeoFile& in, | ||
| 3269 | Mesh& M, | ||
| 3270 | const MeshIOFlags& ioflags = MeshIOFlags() | ||
| 3271 | ) { | ||
| 3272 | |||
| 3273 | 3 | M.clear(); | |
| 3274 | try { | ||
| 3275 | |||
| 3276 | 3 | std::string chunk_class; | |
| 3277 | 3 | for( | |
| 3278 |
2/4✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
|
3 | chunk_class = in.next_chunk(); |
| 3279 |
7/10✓ Branch 1 taken 31 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 28 times.
✓ Branch 4 taken 3 times.
✓ Branch 6 taken 28 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 28 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 28 times.
✓ Branch 11 taken 3 times.
|
31 | chunk_class != "EOFL" && chunk_class != "SPTR"; |
| 3280 |
2/4✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 28 times.
✗ Branch 5 not taken.
|
28 | chunk_class = in.next_chunk() |
| 3281 | ) { | ||
| 3282 | |||
| 3283 |
3/4✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
✓ Branch 4 taken 21 times.
|
28 | if(chunk_class == "ATTS") { |
| 3284 |
1/2✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 | read_attribute_set(in, M, ioflags); |
| 3285 |
3/4✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
✓ Branch 4 taken 12 times.
|
21 | } else if(chunk_class == "ATTR") { |
| 3286 | 9 | if( | |
| 3287 | 18 | String::string_starts_with( | |
| 3288 |
5/8✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 9 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 4 times.
✓ Branch 11 taken 5 times.
|
18 | in.current_attribute().name, "GEO::Mesh::" |
| 3289 | ) | ||
| 3290 | ) { | ||
| 3291 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | read_internal_attribute(in, M, ioflags); |
| 3292 | } else { | ||
| 3293 |
1/2✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
|
5 | read_user_attribute(in, M, ioflags); |
| 3294 | } | ||
| 3295 | } | ||
| 3296 | } | ||
| 3297 | |||
| 3298 | // Create facet "sentry" | ||
| 3299 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
|
3 | if(!M.facets.are_simplices()) { |
| 3300 | ✗ | M.facets.facet_ptr_[M.facets.nb()] = M.facet_corners.nb(); | |
| 3301 | } | ||
| 3302 | |||
| 3303 | // Create cell "sentry" | ||
| 3304 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
|
3 | if(!M.cells.are_simplices()) { |
| 3305 | ✗ | M.cells.cell_ptr_[M.cells.nb()] = M.cell_corners.nb(); | |
| 3306 | } | ||
| 3307 | |||
| 3308 | // This warning when loading a single mesh from a file that may | ||
| 3309 | // contain several meshes -> deactivated for now. | ||
| 3310 | // if(chunk_class == "SPTR") { | ||
| 3311 | // Logger::out("GeoFile") | ||
| 3312 | // << "File may contain several objects" | ||
| 3313 | // << std::endl; | ||
| 3314 | // } | ||
| 3315 | |||
| 3316 |
0/2✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
3 | } catch(const GeoFileException& exc) { |
| 3317 | ✗ | Logger::err("I/O") << exc.what() << std::endl; | |
| 3318 | ✗ | M.clear(); | |
| 3319 | ✗ | return false; | |
| 3320 | ✗ | } catch(...) { | |
| 3321 | ✗ | Logger::err("I/O") << "Caught exception" << std::endl; | |
| 3322 | ✗ | M.clear(); | |
| 3323 | ✗ | return false; | |
| 3324 | ✗ | } | |
| 3325 | |||
| 3326 | // Sanity check for the sentry | ||
| 3327 |
4/10✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 3 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
|
3 | geo_assert( |
| 3328 | M.facets.nb() == 0 || ( | ||
| 3329 | M.facets.corners_end(M.facets.nb()-1) == M.facet_corners.nb() | ||
| 3330 | ) | ||
| 3331 | ); | ||
| 3332 | |||
| 3333 | 3 | return true; | |
| 3334 | } | ||
| 3335 | |||
| 3336 | /** | ||
| 3337 | * \brief Saves a mesh to a GeoFile ('.geogram' file format) | ||
| 3338 | * \details | ||
| 3339 | * Saves mesh \p M to the GeoFile \p geofile. This function can be | ||
| 3340 | * used to write several meshes into the same GeoFile. | ||
| 3341 | * \param[in] M the mesh to save | ||
| 3342 | * \param[in] out a reference to the OutputGeoFile | ||
| 3343 | * \param[in] ioflags specifies which attributes and elements | ||
| 3344 | * should be saved | ||
| 3345 | * \return true on success, false otherwise. | ||
| 3346 | */ | ||
| 3347 | 35 | virtual bool save( | |
| 3348 | const Mesh& M, OutputGeoFile& out, | ||
| 3349 | const MeshIOFlags& ioflags = MeshIOFlags(), | ||
| 3350 | bool save_command_line = false | ||
| 3351 | ) { | ||
| 3352 | try { | ||
| 3353 | |||
| 3354 |
1/2✓ Branch 0 taken 35 times.
✗ Branch 1 not taken.
|
35 | if(save_command_line) { |
| 3355 | // Save command line in file | ||
| 3356 | 35 | std::vector<std::string> args; | |
| 3357 |
1/2✓ Branch 1 taken 35 times.
✗ Branch 2 not taken.
|
35 | CmdLine::get_args(args); |
| 3358 |
1/2✓ Branch 1 taken 35 times.
✗ Branch 2 not taken.
|
35 | out.write_command_line(args); |
| 3359 | 35 | } | |
| 3360 | |||
| 3361 |
3/6✓ Branch 1 taken 35 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 35 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 35 times.
✗ Branch 7 not taken.
|
35 | if(ioflags.has_element(MESH_VERTICES) && M.vertices.nb() != 0) { |
| 3362 |
1/2✓ Branch 2 taken 35 times.
✗ Branch 3 not taken.
|
70 | out.write_attribute_set( |
| 3363 |
1/2✓ Branch 1 taken 35 times.
✗ Branch 2 not taken.
|
70 | "GEO::Mesh::vertices", |
| 3364 | M.vertices.nb() | ||
| 3365 | ); | ||
| 3366 |
1/2✓ Branch 2 taken 35 times.
✗ Branch 3 not taken.
|
70 | save_attributes( |
| 3367 |
1/2✓ Branch 1 taken 35 times.
✗ Branch 2 not taken.
|
105 | out, "GEO::Mesh::vertices", M.vertices.attributes() |
| 3368 | ); | ||
| 3369 | } | ||
| 3370 | |||
| 3371 |
5/6✓ Branch 1 taken 35 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 32 times.
✓ Branch 5 taken 3 times.
✓ Branch 6 taken 32 times.
✓ Branch 7 taken 3 times.
|
35 | if(ioflags.has_element(MESH_EDGES) && M.edges.nb() != 0) { |
| 3372 |
1/2✓ Branch 2 taken 32 times.
✗ Branch 3 not taken.
|
64 | out.write_attribute_set( |
| 3373 |
1/2✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
|
64 | "GEO::Mesh::edges", |
| 3374 | M.edges.nb() | ||
| 3375 | ); | ||
| 3376 | |||
| 3377 |
1/2✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
|
32 | out.write_attribute( |
| 3378 |
1/2✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
|
64 | "GEO::Mesh::edges", |
| 3379 |
1/2✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
|
64 | "GEO::Mesh::edges::edge_vertex", |
| 3380 |
1/2✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
|
64 | "index_t", |
| 3381 | sizeof(index_t), | ||
| 3382 | 2, | ||
| 3383 | 32 | M.edges.edge_vertex_.data() | |
| 3384 | ); | ||
| 3385 | |||
| 3386 |
1/2✓ Branch 2 taken 32 times.
✗ Branch 3 not taken.
|
64 | save_attributes( |
| 3387 |
1/2✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
|
96 | out, "GEO::Mesh::edges", M.edges.attributes() |
| 3388 | ); | ||
| 3389 | } | ||
| 3390 | |||
| 3391 |
5/6✓ Branch 1 taken 35 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 34 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 34 times.
✓ Branch 7 taken 1 times.
|
35 | if(ioflags.has_element(MESH_FACETS) && M.facets.nb() != 0) { |
| 3392 |
1/2✓ Branch 2 taken 34 times.
✗ Branch 3 not taken.
|
68 | out.write_attribute_set( |
| 3393 |
1/2✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
|
68 | "GEO::Mesh::facets", |
| 3394 | M.facets.nb() | ||
| 3395 | ); | ||
| 3396 | |||
| 3397 |
1/2✓ Branch 2 taken 34 times.
✗ Branch 3 not taken.
|
68 | save_attributes( |
| 3398 |
1/2✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
|
68 | out, "GEO::Mesh::facets", M.facets.attributes() |
| 3399 | ); | ||
| 3400 | |||
| 3401 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 34 times.
|
34 | if(!M.facets.are_simplices()) { |
| 3402 | ✗ | out.write_attribute( | |
| 3403 | ✗ | "GEO::Mesh::facets", | |
| 3404 | ✗ | "GEO::Mesh::facets::facet_ptr", | |
| 3405 | ✗ | "index_t", | |
| 3406 | sizeof(index_t), | ||
| 3407 | 1, | ||
| 3408 | ✗ | M.facets.facet_ptr_.data() | |
| 3409 | ); | ||
| 3410 | } | ||
| 3411 | |||
| 3412 |
1/2✓ Branch 2 taken 34 times.
✗ Branch 3 not taken.
|
68 | out.write_attribute_set( |
| 3413 |
1/2✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
|
68 | "GEO::Mesh::facet_corners", |
| 3414 | M.facet_corners.nb() | ||
| 3415 | ); | ||
| 3416 | |||
| 3417 |
1/2✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
|
34 | out.write_attribute( |
| 3418 |
1/2✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
|
68 | "GEO::Mesh::facet_corners", |
| 3419 |
1/2✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
|
68 | "GEO::Mesh::facet_corners::corner_vertex", |
| 3420 |
1/2✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
|
68 | "index_t", |
| 3421 | sizeof(index_t), | ||
| 3422 | 1, | ||
| 3423 | 34 | M.facet_corners.corner_vertex_.data() | |
| 3424 | ); | ||
| 3425 | |||
| 3426 |
1/2✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
|
34 | out.write_attribute( |
| 3427 |
1/2✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
|
68 | "GEO::Mesh::facet_corners", |
| 3428 |
1/2✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
|
68 | "GEO::Mesh::facet_corners::corner_adjacent_facet", |
| 3429 |
1/2✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
|
68 | "index_t", |
| 3430 | sizeof(index_t), | ||
| 3431 | 1, | ||
| 3432 | 34 | M.facet_corners.corner_adjacent_facet_.data() | |
| 3433 | ); | ||
| 3434 | |||
| 3435 |
1/2✓ Branch 2 taken 34 times.
✗ Branch 3 not taken.
|
68 | save_attributes( |
| 3436 |
1/2✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
|
102 | out, "GEO::Mesh::facet_corners", |
| 3437 | M.facet_corners.attributes() | ||
| 3438 | ); | ||
| 3439 | |||
| 3440 | } | ||
| 3441 | |||
| 3442 |
3/6✓ Branch 1 taken 35 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 35 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 35 times.
|
35 | if(ioflags.has_element(MESH_CELLS) && M.cells.nb() != 0) { |
| 3443 | ✗ | out.write_attribute_set( | |
| 3444 | ✗ | "GEO::Mesh::cells", | |
| 3445 | M.cells.nb() | ||
| 3446 | ); | ||
| 3447 | |||
| 3448 | ✗ | save_attributes( | |
| 3449 | ✗ | out, "GEO::Mesh::cells", | |
| 3450 | M.cells.attributes() | ||
| 3451 | ); | ||
| 3452 | |||
| 3453 | ✗ | if(!M.cells.are_simplices()) { | |
| 3454 | |||
| 3455 | ✗ | out.write_attribute( | |
| 3456 | ✗ | "GEO::Mesh::cells", | |
| 3457 | ✗ | "GEO::Mesh::cells::cell_type", | |
| 3458 | ✗ | "char", | |
| 3459 | sizeof(char), | ||
| 3460 | 1, | ||
| 3461 | ✗ | M.cells.cell_type_.data() | |
| 3462 | ); | ||
| 3463 | |||
| 3464 | ✗ | out.write_attribute( | |
| 3465 | ✗ | "GEO::Mesh::cells", | |
| 3466 | ✗ | "GEO::Mesh::cells::cell_ptr", | |
| 3467 | ✗ | "index_t", | |
| 3468 | sizeof(index_t), | ||
| 3469 | 1, | ||
| 3470 | ✗ | M.cells.cell_ptr_.data() | |
| 3471 | ); | ||
| 3472 | } | ||
| 3473 | |||
| 3474 | ✗ | out.write_attribute_set( | |
| 3475 | ✗ | "GEO::Mesh::cell_corners", | |
| 3476 | M.cell_corners.nb() | ||
| 3477 | ); | ||
| 3478 | |||
| 3479 | ✗ | out.write_attribute( | |
| 3480 | ✗ | "GEO::Mesh::cell_corners", | |
| 3481 | ✗ | "GEO::Mesh::cell_corners::corner_vertex", | |
| 3482 | ✗ | "index_t", | |
| 3483 | sizeof(index_t), | ||
| 3484 | 1, | ||
| 3485 | ✗ | M.cell_corners.corner_vertex_.data() | |
| 3486 | ); | ||
| 3487 | |||
| 3488 | ✗ | save_attributes( | |
| 3489 | out, | ||
| 3490 | ✗ | "GEO::Mesh::cell_corners", | |
| 3491 | M.cell_corners.attributes() | ||
| 3492 | ); | ||
| 3493 | |||
| 3494 | ✗ | out.write_attribute_set( | |
| 3495 | ✗ | "GEO::Mesh::cell_facets", | |
| 3496 | M.cell_facets.nb() | ||
| 3497 | ); | ||
| 3498 | |||
| 3499 | ✗ | out.write_attribute( | |
| 3500 | ✗ | "GEO::Mesh::cell_facets", | |
| 3501 | ✗ | "GEO::Mesh::cell_facets::adjacent_cell", | |
| 3502 | ✗ | "index_t", | |
| 3503 | sizeof(index_t), | ||
| 3504 | 1, | ||
| 3505 | ✗ | M.cell_facets.adjacent_cell_.data() | |
| 3506 | ); | ||
| 3507 | |||
| 3508 | ✗ | save_attributes( | |
| 3509 | out, | ||
| 3510 | ✗ | "GEO::Mesh::cell_facets", | |
| 3511 | M.cell_facets.attributes() | ||
| 3512 | ); | ||
| 3513 | } | ||
| 3514 | |||
| 3515 | ✗ | } catch(const GeoFileException& exc) { | |
| 3516 | ✗ | Logger::err("I/O") << exc.what() << std::endl; | |
| 3517 | ✗ | return false; | |
| 3518 | ✗ | } | |
| 3519 | 35 | return true; | |
| 3520 | } | ||
| 3521 | |||
| 3522 | /** | ||
| 3523 | * \copydoc MeshIOHandler::load() | ||
| 3524 | */ | ||
| 3525 | 3 | bool load( | |
| 3526 | const std::string& filename, Mesh& M, | ||
| 3527 | const MeshIOFlags& ioflags = MeshIOFlags() | ||
| 3528 | ) override { | ||
| 3529 | 3 | bool result = true; | |
| 3530 | try { | ||
| 3531 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | InputGeoFile in(filename); |
| 3532 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | result = load(in, M, ioflags); |
| 3533 |
0/2✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
3 | } catch(const GeoFileException& exc) { |
| 3534 | ✗ | Logger::err("I/O") << exc.what() << std::endl; | |
| 3535 | ✗ | result = false; | |
| 3536 | ✗ | } catch(...) { | |
| 3537 | ✗ | Logger::err("I/O") << "Caught exception" << std::endl; | |
| 3538 | ✗ | result = false; | |
| 3539 | ✗ | } | |
| 3540 | 3 | return result; | |
| 3541 | } | ||
| 3542 | |||
| 3543 | /** | ||
| 3544 | * \copydoc MeshIOHandler::save() | ||
| 3545 | */ | ||
| 3546 | 35 | bool save( | |
| 3547 | const Mesh& M, const std::string& filename, | ||
| 3548 | const MeshIOFlags& ioflags = MeshIOFlags() | ||
| 3549 | ) override { | ||
| 3550 | 35 | bool result = true; | |
| 3551 | try { | ||
| 3552 | OutputGeoFile out( | ||
| 3553 | filename, | ||
| 3554 |
2/4✓ Branch 1 taken 35 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 35 times.
✗ Branch 5 not taken.
|
70 | index_t(CmdLine::get_arg_int("sys:compression_level")) |
| 3555 |
1/2✓ Branch 1 taken 35 times.
✗ Branch 2 not taken.
|
35 | ); |
| 3556 |
1/2✓ Branch 1 taken 35 times.
✗ Branch 2 not taken.
|
35 | result = save(M, out, ioflags, true); |
| 3557 |
0/2✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
35 | } catch(const GeoFileException& exc) { |
| 3558 | ✗ | Logger::err("I/O") << exc.what() << std::endl; | |
| 3559 | ✗ | result = false; | |
| 3560 | ✗ | } catch(...) { | |
| 3561 | ✗ | Logger::err("I/O") << "Caught exception" << std::endl; | |
| 3562 | ✗ | result = false; | |
| 3563 | ✗ | } | |
| 3564 | 35 | return result; | |
| 3565 | } | ||
| 3566 | |||
| 3567 | protected: | ||
| 3568 | |||
| 3569 | /** | ||
| 3570 | * \brief Reads an attribute set from a geogram file and | ||
| 3571 | * creates the relevant elements in a mesh. | ||
| 3572 | * \param[in] in a reference to the InputGeoFile | ||
| 3573 | * \param[in] M a reference to the Mesh | ||
| 3574 | * \param[in] ioflags the MeshIOFlags that specify which | ||
| 3575 | * attributes and mesh elements should be read | ||
| 3576 | */ | ||
| 3577 | 7 | void read_attribute_set( | |
| 3578 | InputGeoFile& in, | ||
| 3579 | Mesh& M, | ||
| 3580 | const MeshIOFlags& ioflags | ||
| 3581 | ) { | ||
| 3582 | const std::string& name = | ||
| 3583 | 7 | in.current_attribute_set().name; | |
| 3584 | 7 | index_t nb_items = in.current_attribute_set().nb_items; | |
| 3585 | |||
| 3586 | 7 | if( | |
| 3587 |
5/6✓ Branch 1 taken 3 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
✓ Branch 6 taken 4 times.
|
10 | name == "GEO::Mesh::vertices" && |
| 3588 | 3 | ioflags.has_element(MESH_VERTICES) | |
| 3589 | ) { | ||
| 3590 | 3 | M.vertices.resize_store(nb_items); | |
| 3591 | 4 | } else if( | |
| 3592 |
2/6✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
|
4 | name == "GEO::Mesh::edges" && |
| 3593 | ✗ | ioflags.has_element(MESH_EDGES) | |
| 3594 | ) { | ||
| 3595 | ✗ | M.edges.resize_store(nb_items); | |
| 3596 | 4 | } else if( | |
| 3597 |
5/6✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 2 times.
|
6 | name == "GEO::Mesh::facets" && |
| 3598 | 2 | ioflags.has_element(MESH_FACETS) | |
| 3599 | ) { | ||
| 3600 | 2 | M.facets.resize_store(nb_items); | |
| 3601 | 2 | } else if( | |
| 3602 |
3/6✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
|
4 | name == "GEO::Mesh::facet_corners" && |
| 3603 | 2 | ioflags.has_element(MESH_FACETS) | |
| 3604 | ) { | ||
| 3605 | 2 | M.facet_corners.resize_store(nb_items); | |
| 3606 | ✗ | } else if( | |
| 3607 | ✗ | name == "GEO::Mesh::cells" && | |
| 3608 | ✗ | ioflags.has_element(MESH_CELLS) | |
| 3609 | ) { | ||
| 3610 | ✗ | M.cells.resize_store(nb_items); | |
| 3611 | ✗ | } else if( | |
| 3612 | ✗ | name == "GEO::Mesh::cell_corners" && | |
| 3613 | ✗ | ioflags.has_element(MESH_CELLS) | |
| 3614 | ) { | ||
| 3615 | ✗ | M.cell_corners.resize_store(nb_items); | |
| 3616 | ✗ | } else if( | |
| 3617 | ✗ | name == "GEO::Mesh::cell_facets" && | |
| 3618 | ✗ | ioflags.has_element(MESH_CELLS) | |
| 3619 | ) { | ||
| 3620 | ✗ | M.cell_facets.resize_store(nb_items); | |
| 3621 | } | ||
| 3622 | 7 | } | |
| 3623 | |||
| 3624 | /** | ||
| 3625 | * \brief Reads a user attribute from a geogram file and | ||
| 3626 | * stores it in a mesh. | ||
| 3627 | * \param[in] in a reference to the InputGeoFile | ||
| 3628 | * \param[in] M a reference to the Mesh | ||
| 3629 | * \param[in] ioflags the MeshIOFlags that specify which | ||
| 3630 | * attributes and mesh elements should be read | ||
| 3631 | */ | ||
| 3632 | 5 | void read_user_attribute( | |
| 3633 | InputGeoFile& in, | ||
| 3634 | Mesh& M, | ||
| 3635 | const MeshIOFlags& ioflags | ||
| 3636 | ) { | ||
| 3637 | const std::string& name = | ||
| 3638 | 5 | in.current_attribute().name; | |
| 3639 | const std::string& set_name = | ||
| 3640 | 5 | in.current_attribute_set().name; | |
| 3641 |
2/2✓ Branch 1 taken 3 times.
✓ Branch 2 taken 2 times.
|
5 | if(set_name == "GEO::Mesh::vertices") { |
| 3642 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | if(ioflags.has_element(MESH_VERTICES)) { |
| 3643 | // Vertex geometry is a special attribute, already | ||
| 3644 | // created by the Mesh class, therefore we cannot use | ||
| 3645 | // the generic read_attribute() function. | ||
| 3646 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | if(name == "point") { |
| 3647 | 3 | M.vertices.set_double_precision(); | |
| 3648 | 6 | M.vertices.set_dimension( | |
| 3649 | 3 | in.current_attribute().dimension | |
| 3650 | ); | ||
| 3651 | 3 | in.read_attribute(M.vertices.point_ptr(0)); | |
| 3652 | ✗ | } else if(name == "point_fp32") { | |
| 3653 | ✗ | M.vertices.set_single_precision(); | |
| 3654 | ✗ | M.vertices.set_dimension( | |
| 3655 | ✗ | in.current_attribute().dimension | |
| 3656 | ); | ||
| 3657 | ✗ | in.read_attribute( | |
| 3658 | ✗ | M.vertices.single_precision_point_ptr(0) | |
| 3659 | ); | ||
| 3660 | } else { | ||
| 3661 | ✗ | read_attribute(in, M.vertices.attributes()); | |
| 3662 | } | ||
| 3663 | } | ||
| 3664 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
2 | } else if(set_name == "GEO::Mesh::edges") { |
| 3665 | ✗ | if(ioflags.has_element(MESH_EDGES)) { | |
| 3666 | ✗ | read_attribute(in, M.edges.attributes()); | |
| 3667 | } | ||
| 3668 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
2 | } else if(set_name == "GEO::Mesh::facets") { |
| 3669 | ✗ | if(ioflags.has_element(MESH_FACETS)) { | |
| 3670 | ✗ | read_attribute(in, M.facets.attributes()); | |
| 3671 | } | ||
| 3672 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | } else if(set_name == "GEO::Mesh::facet_corners") { |
| 3673 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if(ioflags.has_element(MESH_FACETS)) { |
| 3674 | 2 | read_attribute( | |
| 3675 | in, M.facet_corners.attributes() | ||
| 3676 | ); | ||
| 3677 | } | ||
| 3678 | ✗ | } else if(set_name == "GEO::Mesh::cells") { | |
| 3679 | ✗ | if(ioflags.has_element(MESH_CELLS)) { | |
| 3680 | ✗ | read_attribute(in, M.cells.attributes()); | |
| 3681 | } | ||
| 3682 | ✗ | } else if(set_name == "GEO::Mesh::cell_corners") { | |
| 3683 | ✗ | if(ioflags.has_element(MESH_CELLS)) { | |
| 3684 | ✗ | read_attribute(in, M.cell_corners.attributes()); | |
| 3685 | } | ||
| 3686 | ✗ | } else if(set_name == "GEO::Mesh::cell_facets") { | |
| 3687 | ✗ | if(ioflags.has_element(MESH_CELLS)) { | |
| 3688 | ✗ | read_attribute(in, M.cell_facets.attributes()); | |
| 3689 | } | ||
| 3690 | } | ||
| 3691 | 5 | } | |
| 3692 | |||
| 3693 | /** | ||
| 3694 | * \brief Reads an internal attribute from a geogram file and | ||
| 3695 | * stores it in a mesh. | ||
| 3696 | * \param[in] in a reference to the InputGeoFile | ||
| 3697 | * \param[in] M a reference to the Mesh | ||
| 3698 | * \param[in] ioflags the MeshIOFlags that specify which | ||
| 3699 | * attributes and mesh elements should be read | ||
| 3700 | */ | ||
| 3701 | 4 | void read_internal_attribute( | |
| 3702 | InputGeoFile& in, | ||
| 3703 | Mesh& M, | ||
| 3704 | const MeshIOFlags& ioflags | ||
| 3705 | ) { | ||
| 3706 | const std::string& name = | ||
| 3707 | 4 | in.current_attribute().name; | |
| 3708 | |||
| 3709 | const std::string& set_name = | ||
| 3710 | 4 | in.current_attribute_set().name; | |
| 3711 | |||
| 3712 |
3/6✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 4 times.
|
4 | if(!String::string_starts_with(name, set_name + "::")) { |
| 3713 | ✗ | Logger::warn("I/O") | |
| 3714 | << "Invalid internal attribute (GEO::Mesh:: scoped): " | ||
| 3715 | << name << " does not start with " | ||
| 3716 | ✗ | << set_name | |
| 3717 | ✗ | << std::endl; | |
| 3718 | ✗ | return; | |
| 3719 | } | ||
| 3720 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
|
4 | if(name == "GEO::Mesh::edges::edge_vertex") { |
| 3721 | ✗ | if(ioflags.has_element(MESH_EDGES)) { | |
| 3722 | ✗ | M.edges.edge_vertex_.resize(M.edges.nb()*2); | |
| 3723 | ✗ | in.read_attribute(M.edges.edge_vertex_.data()); | |
| 3724 | } | ||
| 3725 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
|
4 | } else if(name == "GEO::Mesh::facets::facet_ptr") { |
| 3726 | ✗ | if(ioflags.has_element(MESH_FACETS)) { | |
| 3727 | ✗ | M.facets.is_simplicial_ = false; | |
| 3728 | ✗ | M.facets.facet_ptr_.resize(M.facets.nb()+1); | |
| 3729 | ✗ | in.read_attribute(M.facets.facet_ptr_.data()); | |
| 3730 | } | ||
| 3731 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
|
4 | } else if(name == "GEO::Mesh::facet_corners::corner_vertex") { |
| 3732 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if(ioflags.has_element(MESH_FACETS)) { |
| 3733 | 2 | in.read_attribute(M.facet_corners.corner_vertex_.data()); | |
| 3734 | } | ||
| 3735 | 2 | } else if( | |
| 3736 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | name == "GEO::Mesh::facet_corners::corner_adjacent_facet" |
| 3737 | ) { | ||
| 3738 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if(ioflags.has_element(MESH_FACETS)) { |
| 3739 | 2 | in.read_attribute( | |
| 3740 | 2 | M.facet_corners.corner_adjacent_facet_.data() | |
| 3741 | ); | ||
| 3742 | } | ||
| 3743 | ✗ | } else if(name == "GEO::Mesh::cells::cell_type") { | |
| 3744 | ✗ | if(ioflags.has_element(MESH_CELLS)) { | |
| 3745 | ✗ | M.cells.is_simplicial_ = false; | |
| 3746 | ✗ | M.cells.cell_type_.resize(M.cells.nb()); | |
| 3747 | ✗ | in.read_attribute(M.cells.cell_type_.data()); | |
| 3748 | } | ||
| 3749 | ✗ | } else if(name == "GEO::Mesh::cells::cell_ptr") { | |
| 3750 | ✗ | if(ioflags.has_element(MESH_CELLS)) { | |
| 3751 | ✗ | M.cells.is_simplicial_ = false; | |
| 3752 | ✗ | M.cells.cell_ptr_.resize(M.cells.nb()+1); | |
| 3753 | ✗ | in.read_attribute(M.cells.cell_ptr_.data()); | |
| 3754 | } | ||
| 3755 | ✗ | } else if(name == "GEO::Mesh::cell_corners::corner_vertex") { | |
| 3756 | ✗ | if(ioflags.has_element(MESH_CELLS)) { | |
| 3757 | ✗ | in.read_attribute(M.cell_corners.corner_vertex_.data()); | |
| 3758 | } | ||
| 3759 | ✗ | } else if(name == "GEO::Mesh::cell_facets::adjacent_cell") { | |
| 3760 | ✗ | if(ioflags.has_element(MESH_CELLS)) { | |
| 3761 | ✗ | in.read_attribute(M.cell_facets.adjacent_cell_.data()); | |
| 3762 | } | ||
| 3763 | } | ||
| 3764 | } | ||
| 3765 | |||
| 3766 | /** | ||
| 3767 | * \brief Reads a user attribute from a geogram file and | ||
| 3768 | * stores it in an AttributesManager | ||
| 3769 | * \param[in] in a reference to the InputGeoFile | ||
| 3770 | * \param[in] attributes a reference to the AttributesManager | ||
| 3771 | * where the read attribute should be stored | ||
| 3772 | */ | ||
| 3773 | 2 | void read_attribute( | |
| 3774 | InputGeoFile& in, | ||
| 3775 | AttributesManager& attributes | ||
| 3776 | ) { | ||
| 3777 | 2 | if( | |
| 3778 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | !AttributeStore::element_type_name_is_known( |
| 3779 | 2 | in.current_attribute().element_type | |
| 3780 | ) | ||
| 3781 | ) { | ||
| 3782 | ✗ | Logger::warn("I/O") | |
| 3783 | << "Skipping attribute " | ||
| 3784 | ✗ | << in.current_attribute().name | |
| 3785 | << ":" | ||
| 3786 | ✗ | << demangle(in.current_attribute().element_type) | |
| 3787 | ✗ | << " (unknown type)" | |
| 3788 | ✗ | << std::endl; | |
| 3789 | ✗ | return; | |
| 3790 | } | ||
| 3791 | AttributeStore* store = | ||
| 3792 | 4 | AttributeStore::create_attribute_store_by_element_type_name( | |
| 3793 | 2 | in.current_attribute().element_type, | |
| 3794 | 2 | in.current_attribute().dimension | |
| 3795 | ); | ||
| 3796 | 2 | attributes.bind_attribute_store(in.current_attribute().name,store); | |
| 3797 | 2 | in.read_attribute(store->data()); | |
| 3798 | } | ||
| 3799 | |||
| 3800 | /** | ||
| 3801 | * \brief Writes all the user attributes of an AttributesManager | ||
| 3802 | * into a geogram file. | ||
| 3803 | * \param[out] out a reference to the OutputGeoFile | ||
| 3804 | * \param[in] attribute_set_name the name to be used for the attribute | ||
| 3805 | * set in the geogram file | ||
| 3806 | * \param[in] attributes a reference to the AttributesManager | ||
| 3807 | */ | ||
| 3808 | 135 | void save_attributes( | |
| 3809 | OutputGeoFile& out, | ||
| 3810 | const std::string& attribute_set_name, | ||
| 3811 | AttributesManager& attributes | ||
| 3812 | ) { | ||
| 3813 | 135 | vector<std::string> attribute_names; | |
| 3814 |
1/2✓ Branch 1 taken 135 times.
✗ Branch 2 not taken.
|
135 | attributes.list_attribute_names(attribute_names); |
| 3815 |
2/2✓ Branch 1 taken 37 times.
✓ Branch 2 taken 135 times.
|
172 | for(index_t i=0; i<attribute_names.size(); ++i) { |
| 3816 | 74 | AttributeStore* store = attributes.find_attribute_store( | |
| 3817 |
2/4✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 37 times.
✗ Branch 5 not taken.
|
37 | attribute_names[i] |
| 3818 | ); | ||
| 3819 | 37 | if( | |
| 3820 | 74 | AttributeStore::element_typeid_name_is_known( | |
| 3821 |
1/4✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
37 | store->element_typeid_name() |
| 3822 |
3/6✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 37 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 37 times.
✗ Branch 7 not taken.
|
74 | ) && |
| 3823 |
2/4✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 37 times.
✗ Branch 4 not taken.
|
37 | AttributeStore::element_by_typeid_name_is_trivially_copyable( |
| 3824 |
3/8✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 37 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 37 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
|
74 | store->element_typeid_name() |
| 3825 | ) | ||
| 3826 | ) { | ||
| 3827 | std::string element_type = | ||
| 3828 | AttributeStore::element_type_name_by_element_typeid_name( | ||
| 3829 |
1/2✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
|
74 | store->user_element_typeid_name() |
| 3830 |
1/2✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
|
37 | ); |
| 3831 | |||
| 3832 | 37 | out.write_attribute( | |
| 3833 | attribute_set_name, | ||
| 3834 |
2/4✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 37 times.
✗ Branch 5 not taken.
|
37 | attribute_names[i], |
| 3835 | element_type, | ||
| 3836 | store->element_size(), | ||
| 3837 | store->dimension(), | ||
| 3838 | 37 | store->data() | |
| 3839 | ); | ||
| 3840 | 37 | } else { | |
| 3841 | ✗ | Logger::warn("I/O") | |
| 3842 | << "Skipping attribute: " | ||
| 3843 | ✗ | << attribute_names[i] | |
| 3844 | << " on " | ||
| 3845 | ✗ | << attribute_set_name | |
| 3846 | ✗ | << std::endl; | |
| 3847 | |||
| 3848 | ✗ | Logger::warn("I/O") | |
| 3849 | << "Unsupported type: " | ||
| 3850 | ✗ | << demangle(store->element_typeid_name()) | |
| 3851 | ✗ | << std::endl; | |
| 3852 | } | ||
| 3853 | } | ||
| 3854 | 135 | } | |
| 3855 | }; | ||
| 3856 | |||
| 3857 | /************************************************************************/ | ||
| 3858 | |||
| 3859 | /** | ||
| 3860 | * \brief IO handler for graphite files. | ||
| 3861 | * \details Graphite files with a single object can be directly read | ||
| 3862 | * by geogram. | ||
| 3863 | */ | ||
| 3864 | class GraphiteIOHandler : public GeogramIOHandler { | ||
| 3865 | public: | ||
| 3866 | /** | ||
| 3867 | * \copydoc MeshIOHandler::save() | ||
| 3868 | */ | ||
| 3869 | ✗ | bool save( | |
| 3870 | const Mesh& M, const std::string& filename, | ||
| 3871 | const MeshIOFlags& ioflags = MeshIOFlags() | ||
| 3872 | ) override { | ||
| 3873 | ✗ | geo_argused(M); | |
| 3874 | ✗ | geo_argused(filename); | |
| 3875 | ✗ | geo_argused(ioflags); | |
| 3876 | ✗ | Logger::err("I/O") | |
| 3877 | ✗ | << "graphite file format not supported for writing" | |
| 3878 | ✗ | << std::endl; | |
| 3879 | ✗ | return false; | |
| 3880 | } | ||
| 3881 | |||
| 3882 | /** | ||
| 3883 | * \copydoc MeshIOHandler::save() | ||
| 3884 | */ | ||
| 3885 | ✗ | bool save( | |
| 3886 | const Mesh& M, OutputGeoFile& out, | ||
| 3887 | const MeshIOFlags& ioflags = MeshIOFlags(), | ||
| 3888 | bool save_command_line = false | ||
| 3889 | ) override { | ||
| 3890 | ✗ | geo_argused(M); | |
| 3891 | ✗ | geo_argused(out); | |
| 3892 | ✗ | geo_argused(ioflags); | |
| 3893 | ✗ | geo_argused(save_command_line); | |
| 3894 | ✗ | Logger::err("I/O") | |
| 3895 | ✗ | << "graphite file format not supported for writing" | |
| 3896 | ✗ | << std::endl; | |
| 3897 | ✗ | return false; | |
| 3898 | } | ||
| 3899 | }; | ||
| 3900 | |||
| 3901 | /************************************************************************/ | ||
| 3902 | |||
| 3903 | /** | ||
| 3904 | * \brief IO handler for PDB (Protein DataBase) files. | ||
| 3905 | */ | ||
| 3906 | class PDBIOHandler : public MeshIOHandler { | ||
| 3907 | public: | ||
| 3908 | ✗ | bool load( | |
| 3909 | const std::string& filename, Mesh& M, | ||
| 3910 | const MeshIOFlags& ioflags | ||
| 3911 | ) override { | ||
| 3912 | ✗ | geo_argused(ioflags); | |
| 3913 | ✗ | M.clear(); | |
| 3914 | ✗ | M.vertices.set_dimension(3); | |
| 3915 | ✗ | std::ifstream in(filename.c_str()); | |
| 3916 | ✗ | if(!in) { | |
| 3917 | ✗ | return false; | |
| 3918 | } | ||
| 3919 | ✗ | Attribute<char> atom_type(M.vertices.attributes(), "atom_type"); | |
| 3920 | ✗ | Attribute<char> chain_id(M.vertices.attributes(), "chain_id"); | |
| 3921 | ✗ | while(in) { | |
| 3922 | ✗ | std::string line; | |
| 3923 | ✗ | getline(in, line); | |
| 3924 | ✗ | while(line.length() < 80) { | |
| 3925 | ✗ | line.push_back(' '); | |
| 3926 | } | ||
| 3927 | ✗ | std::string record_name = get_columns(line, 1, 6) ; | |
| 3928 | ✗ | if(record_name == "ATOM " || record_name == "HETATM") { | |
| 3929 | ✗ | std::string serial = get_columns(line, 7, 11); | |
| 3930 | ✗ | std::string name = get_columns(line, 11, 16); | |
| 3931 | ✗ | std::string altLoc = get_columns(line, 17, 17); | |
| 3932 | ✗ | std::string resName = get_columns(line, 18, 20); | |
| 3933 | ✗ | std::string chainID = get_columns(line, 22, 22); | |
| 3934 | ✗ | std::string resSeq = get_columns(line, 23, 26); | |
| 3935 | ✗ | std::string iCode = get_columns(line, 27, 27); | |
| 3936 | ✗ | double x = to_double(get_columns(line, 31, 38)); | |
| 3937 | ✗ | double y = to_double(get_columns(line, 39, 46)); | |
| 3938 | ✗ | double z = to_double(get_columns(line, 47, 54)); | |
| 3939 | //double occupancy = to_double(get_columns(line, 55, 60)); | ||
| 3940 | //double tempFactor = to_double(get_columns(line, 61, 66)); | ||
| 3941 | ✗ | std::string element = get_columns(line, 77, 78); | |
| 3942 | ✗ | std::string charge = get_columns(line, 79, 80); | |
| 3943 | |||
| 3944 | ✗ | index_t v = M.vertices.create_vertex(); | |
| 3945 | ✗ | if(M.vertices.single_precision()) { | |
| 3946 | ✗ | M.vertices.single_precision_point_ptr(v)[0] = float(x); | |
| 3947 | ✗ | M.vertices.single_precision_point_ptr(v)[1] = float(y); | |
| 3948 | ✗ | M.vertices.single_precision_point_ptr(v)[2] = float(z); | |
| 3949 | } else { | ||
| 3950 | ✗ | M.vertices.point_ptr(v)[0] = x; | |
| 3951 | ✗ | M.vertices.point_ptr(v)[1] = y; | |
| 3952 | ✗ | M.vertices.point_ptr(v)[2] = z; | |
| 3953 | } | ||
| 3954 | ✗ | atom_type[v] = name[3]; | |
| 3955 | ✗ | chain_id[v] = chainID[0]; | |
| 3956 | ✗ | } | |
| 3957 | ✗ | } | |
| 3958 | ✗ | return true; | |
| 3959 | ✗ | } | |
| 3960 | |||
| 3961 | /** | ||
| 3962 | * \copydoc MeshIOHandler::save() | ||
| 3963 | */ | ||
| 3964 | ✗ | bool save( | |
| 3965 | const Mesh& M, const std::string& filename, | ||
| 3966 | const MeshIOFlags& ioflags = MeshIOFlags() | ||
| 3967 | ) override { | ||
| 3968 | ✗ | geo_argused(M); | |
| 3969 | ✗ | geo_argused(filename); | |
| 3970 | ✗ | geo_argused(ioflags); | |
| 3971 | ✗ | Logger::err("I/O") | |
| 3972 | ✗ | << "PDB file format not supported for writing" | |
| 3973 | ✗ | << std::endl; | |
| 3974 | ✗ | return false; | |
| 3975 | } | ||
| 3976 | protected: | ||
| 3977 | |||
| 3978 | ✗ | inline std::string get_columns( | |
| 3979 | const std::string& s, unsigned int from_c, unsigned int to_c | ||
| 3980 | ) const { | ||
| 3981 | ✗ | return s.substr(from_c - 1, to_c - from_c + 1) ; | |
| 3982 | } | ||
| 3983 | |||
| 3984 | ✗ | inline double to_double(const std::string& s) { | |
| 3985 | ✗ | return String::to_double(s); | |
| 3986 | } | ||
| 3987 | }; | ||
| 3988 | |||
| 3989 | /************************************************************************/ | ||
| 3990 | |||
| 3991 | /** | ||
| 3992 | * \brief Mesh IO Handler for OpenVolumeMesh file format. | ||
| 3993 | * \details Saves a polyhedral mesh stored in a surfacic mesh that | ||
| 3994 | * has all cell boundaries and a vertex_id vertex attribute and cell_id | ||
| 3995 | * facet attribute. Note: the implementation is pretty inefficient (uses | ||
| 3996 | * tables). | ||
| 3997 | */ | ||
| 3998 | class OVMIOHandler : public MeshIOHandler { | ||
| 3999 | public: | ||
| 4000 | /** | ||
| 4001 | * \copydoc MeshIOHandler::load() | ||
| 4002 | */ | ||
| 4003 | ✗ | bool load( | |
| 4004 | const std::string& filename, Mesh& M, | ||
| 4005 | const MeshIOFlags& ioflags | ||
| 4006 | ) override { | ||
| 4007 | ✗ | geo_argused(ioflags); | |
| 4008 | ✗ | M.clear(); | |
| 4009 | ✗ | M.vertices.set_dimension(3); | |
| 4010 | ✗ | LineInput in(filename); | |
| 4011 | ✗ | if(!in.OK()) { | |
| 4012 | ✗ | return false; | |
| 4013 | } | ||
| 4014 | |||
| 4015 | ✗ | in.get_line(); | |
| 4016 | ✗ | in.get_fields(); | |
| 4017 | ✗ | if( | |
| 4018 | ✗ | in.nb_fields() != 2 || | |
| 4019 | ✗ | strcmp(in.field(0),"OVM") || | |
| 4020 | ✗ | strcmp(in.field(1),"ASCII") | |
| 4021 | ) { | ||
| 4022 | ✗ | Logger::err("OVM") << "Invalid file header" << std::endl; | |
| 4023 | ✗ | return false; | |
| 4024 | } | ||
| 4025 | |||
| 4026 | |||
| 4027 | ✗ | Attribute<int> vertex_id(M.vertices.attributes(), "vertex_id"); | |
| 4028 | ✗ | Attribute<int> cell_id(M.facets.attributes(), "cell_id"); | |
| 4029 | |||
| 4030 | ✗ | index_t nb_vertices = 0; | |
| 4031 | ✗ | vector<double> vertices; | |
| 4032 | ✗ | vector<index_t> ovm_to_vertex_id; | |
| 4033 | |||
| 4034 | ✗ | index_t nb_edges = 0; | |
| 4035 | ✗ | vector<index_t> edges; | |
| 4036 | |||
| 4037 | ✗ | index_t nb_facets = 0; | |
| 4038 | ✗ | vector<index_t> facet_ptr; | |
| 4039 | ✗ | vector<index_t> facet_edge; | |
| 4040 | |||
| 4041 | ✗ | index_t nb_cells = 0; | |
| 4042 | |||
| 4043 | try { | ||
| 4044 | ✗ | while(!in.eof()) { | |
| 4045 | ✗ | std::string kw = get_keyword(in); | |
| 4046 | ✗ | if(kw == "Vertices") { | |
| 4047 | ✗ | nb_vertices = get_number(in); | |
| 4048 | ✗ | vertices.resize(nb_vertices*3); | |
| 4049 | ✗ | ovm_to_vertex_id.assign(nb_vertices*3, NO_INDEX); | |
| 4050 | ✗ | FOR(v, nb_vertices) { | |
| 4051 | ✗ | in.get_line(); | |
| 4052 | ✗ | in.get_fields(); | |
| 4053 | ✗ | if(in.nb_fields() != 3) { | |
| 4054 | throw( | ||
| 4055 | ✗ | "Line: " + | |
| 4056 | ✗ | String::to_string(in.line_number()) + | |
| 4057 | ":Invalid vertex, expected 3 coordinates" | ||
| 4058 | ✗ | ); | |
| 4059 | } | ||
| 4060 | ✗ | vertices[3*v] = in.field_as_double(0); | |
| 4061 | ✗ | vertices[3*v+1] = in.field_as_double(1); | |
| 4062 | ✗ | vertices[3*v+2] = in.field_as_double(2); | |
| 4063 | } | ||
| 4064 | ✗ | } else if(kw == "Edges") { | |
| 4065 | ✗ | nb_edges = get_number(in); | |
| 4066 | ✗ | edges.resize(nb_edges*2); | |
| 4067 | ✗ | FOR(e, nb_edges) { | |
| 4068 | ✗ | in.get_line(); | |
| 4069 | ✗ | in.get_fields(); | |
| 4070 | ✗ | if(in.nb_fields() != 2) { | |
| 4071 | throw( | ||
| 4072 | ✗ | "Line: " + | |
| 4073 | ✗ | String::to_string(in.line_number()) + | |
| 4074 | ":Invalid edge, expected 2 indices" | ||
| 4075 | ✗ | ); | |
| 4076 | } | ||
| 4077 | ✗ | edges[2*e] = in.field_as_uint(0); | |
| 4078 | ✗ | edges[2*e+1] = in.field_as_uint(1); | |
| 4079 | ✗ | if( | |
| 4080 | ✗ | edges[2*e] >= nb_vertices || | |
| 4081 | ✗ | edges[2*e+1] >= nb_vertices) { | |
| 4082 | throw( | ||
| 4083 | ✗ | "Line: " + | |
| 4084 | ✗ | String::to_string(in.line_number()) + | |
| 4085 | ":Invalid vertex id in edge" | ||
| 4086 | ✗ | ); | |
| 4087 | } | ||
| 4088 | } | ||
| 4089 | ✗ | } else if(kw == "Faces") { | |
| 4090 | ✗ | nb_facets = get_number(in); | |
| 4091 | ✗ | facet_ptr.resize(nb_facets+1); | |
| 4092 | ✗ | facet_ptr[0] = 0; | |
| 4093 | ✗ | FOR(f, nb_facets) { | |
| 4094 | ✗ | in.get_line(); | |
| 4095 | ✗ | in.get_fields(); | |
| 4096 | ✗ | if(in.nb_fields() == 0) { | |
| 4097 | throw( | ||
| 4098 | ✗ | "Line: " + | |
| 4099 | ✗ | String::to_string(in.line_number()) + | |
| 4100 | ":Invalid facet, empty line" | ||
| 4101 | ✗ | ); | |
| 4102 | } | ||
| 4103 | ✗ | index_t facet_size = in.field_as_uint(0); | |
| 4104 | ✗ | facet_ptr[f+1] = facet_ptr[f] + facet_size; | |
| 4105 | ✗ | if(in.nb_fields() != facet_size+1) { | |
| 4106 | throw( | ||
| 4107 | ✗ | "Line: " + | |
| 4108 | ✗ | String::to_string(in.line_number()) + | |
| 4109 | ":Invalid facet, wrong number of elements" | ||
| 4110 | ✗ | ); | |
| 4111 | } | ||
| 4112 | ✗ | FOR(lf, facet_size) { | |
| 4113 | ✗ | index_t ie = in.field_as_uint(1+lf); | |
| 4114 | ✗ | if((ie/2) >= nb_edges) { | |
| 4115 | throw( | ||
| 4116 | ✗ | "Line: " + | |
| 4117 | ✗ | String::to_string(in.line_number()) + | |
| 4118 | ":Invalid edge id in facet" | ||
| 4119 | ✗ | ); | |
| 4120 | } | ||
| 4121 | ✗ | facet_edge.push_back(ie); | |
| 4122 | } | ||
| 4123 | } | ||
| 4124 | ✗ | } else if(kw == "Polyhedra") { | |
| 4125 | ✗ | nb_cells = get_number(in); | |
| 4126 | ✗ | FOR(c, nb_cells) { | |
| 4127 | ✗ | in.get_line(); | |
| 4128 | ✗ | in.get_fields(); | |
| 4129 | ✗ | if(in.nb_fields() == 0) { | |
| 4130 | throw( | ||
| 4131 | ✗ | "Line: " + | |
| 4132 | ✗ | String::to_string(in.line_number()) + | |
| 4133 | ":Invalid cell, empty line" | ||
| 4134 | ✗ | ); | |
| 4135 | } | ||
| 4136 | ✗ | index_t cell_size = in.field_as_uint(0); | |
| 4137 | ✗ | if(in.nb_fields() != cell_size + 1) { | |
| 4138 | throw( | ||
| 4139 | ✗ | "Line: " + | |
| 4140 | ✗ | String::to_string(in.line_number()) + | |
| 4141 | ":Invalid cell, wrong number of elements" | ||
| 4142 | ✗ | ); | |
| 4143 | } | ||
| 4144 | ✗ | vector<index_t> cell_facets; | |
| 4145 | ✗ | FOR(lf, cell_size) { | |
| 4146 | ✗ | index_t f = in.field_as_uint(lf+1); | |
| 4147 | ✗ | if((f/2) >= nb_facets) { | |
| 4148 | throw( | ||
| 4149 | ✗ | "Line: " + | |
| 4150 | ✗ | String::to_string(in.line_number()) + | |
| 4151 | ":Invalid facet id in cell" | ||
| 4152 | ✗ | ); | |
| 4153 | } | ||
| 4154 | ✗ | cell_facets.push_back(f); | |
| 4155 | } | ||
| 4156 | |||
| 4157 | // Clear vertex ids | ||
| 4158 | ✗ | FOR(lf, cell_size) { | |
| 4159 | ✗ | index_t f = cell_facets[lf]; | |
| 4160 | ✗ | bool inverse_f = (f & 1) != 0; | |
| 4161 | ✗ | f /= 2; | |
| 4162 | ✗ | for(index_t ee = facet_ptr[f]; ee<facet_ptr[f+1]; ++ee) { | |
| 4163 | ✗ | index_t e = facet_edge[ee]; | |
| 4164 | ✗ | if(inverse_f) { | |
| 4165 | ✗ | e = e ^ index_t(1); | |
| 4166 | } | ||
| 4167 | // Vertex index is directly obtained from edge[] | ||
| 4168 | // (edge2vertices) table, and rule for orientation | ||
| 4169 | // (2*e for direct edge, 2*e+1 for inversed edge) | ||
| 4170 | // directly gives the index of the origin vertex. | ||
| 4171 | // If the facet is inversed, then the edge is inversed | ||
| 4172 | // (by inverting its least significant bit, with the | ||
| 4173 | // XOR e ^(index_t(1)) operation). | ||
| 4174 | ✗ | index_t ovm_v = edges[e]; | |
| 4175 | ✗ | ovm_to_vertex_id[ ovm_v ] = NO_INDEX; | |
| 4176 | } | ||
| 4177 | } | ||
| 4178 | |||
| 4179 | // Create vertices | ||
| 4180 | ✗ | FOR(lf, cell_size) { | |
| 4181 | ✗ | index_t f = cell_facets[lf]; | |
| 4182 | ✗ | bool inverse_f = (f & 1) != 0; | |
| 4183 | ✗ | f /= 2; | |
| 4184 | ✗ | for(index_t ee = facet_ptr[f]; ee<facet_ptr[f+1]; ++ee) { | |
| 4185 | ✗ | index_t e = facet_edge[ee]; | |
| 4186 | ✗ | if(inverse_f) { | |
| 4187 | ✗ | e = e ^ index_t(1); | |
| 4188 | } | ||
| 4189 | ✗ | index_t ovm_v = edges[e]; | |
| 4190 | ✗ | if(ovm_to_vertex_id[ovm_v] == NO_INDEX) { | |
| 4191 | ✗ | const double* p = &(vertices[ ovm_v*3 ]); | |
| 4192 | ✗ | index_t new_v = M.vertices.create_vertex(); | |
| 4193 | ✗ | set_mesh_point(M, new_v, p, 3); | |
| 4194 | ✗ | ovm_to_vertex_id[ovm_v] = new_v; | |
| 4195 | ✗ | vertex_id[new_v] = int(ovm_v); | |
| 4196 | } | ||
| 4197 | } | ||
| 4198 | } | ||
| 4199 | |||
| 4200 | // Create facets | ||
| 4201 | ✗ | FOR(lf, cell_size) { | |
| 4202 | ✗ | index_t f = cell_facets[lf]; | |
| 4203 | ✗ | bool inverse_f = (f & 1) != 0; | |
| 4204 | ✗ | f /= 2; | |
| 4205 | ✗ | index_t facet_size = facet_ptr[f+1] - facet_ptr[f]; | |
| 4206 | ✗ | index_t new_f = M.facets.create_polygon(facet_size); | |
| 4207 | ✗ | cell_id[new_f] = int(c); | |
| 4208 | ✗ | FOR(le, facet_size) { | |
| 4209 | ✗ | index_t ee = inverse_f ? | |
| 4210 | ✗ | (facet_ptr[f+1] - le - 1) : | |
| 4211 | ✗ | (facet_ptr[f] + le); | |
| 4212 | ✗ | index_t e = facet_edge[ee]; | |
| 4213 | ✗ | if(inverse_f) { | |
| 4214 | ✗ | e = e ^ index_t(1); | |
| 4215 | } | ||
| 4216 | ✗ | index_t ovm_v = edges[e]; | |
| 4217 | ✗ | index_t geo_v = ovm_to_vertex_id[ovm_v]; | |
| 4218 | ✗ | M.facets.set_vertex(new_f, le, geo_v); | |
| 4219 | } | ||
| 4220 | } | ||
| 4221 | ✗ | } | |
| 4222 | ✗ | } else if(kw == "Vertex_Property") { | |
| 4223 | ✗ | skip_property(in,nb_vertices); | |
| 4224 | ✗ | } else if(kw == "Edge_Property") { | |
| 4225 | ✗ | skip_property(in,nb_edges); | |
| 4226 | ✗ | } else if(kw == "HalfEdge_Property") { | |
| 4227 | ✗ | skip_property(in,nb_edges*2); | |
| 4228 | ✗ | } else if(kw == "Face_Property") { | |
| 4229 | ✗ | skip_property(in,nb_facets); | |
| 4230 | ✗ | } else if(kw == "HalfFace_Property") { | |
| 4231 | ✗ | skip_property(in,nb_facets*2); | |
| 4232 | ✗ | } else if(kw == "Polyhedron_Property") { | |
| 4233 | ✗ | skip_property(in,nb_cells); | |
| 4234 | } | ||
| 4235 | ✗ | } | |
| 4236 | ✗ | } catch(const std::string& what) { | |
| 4237 | ✗ | Logger::err("I/O") << what << std::endl; | |
| 4238 | ✗ | return false; | |
| 4239 | ✗ | } catch(const std::exception& ex) { | |
| 4240 | ✗ | Logger::err("I/O") << ex.what() << std::endl; | |
| 4241 | ✗ | return false; | |
| 4242 | ✗ | } catch(...) { | |
| 4243 | ✗ | Logger::err("I/O") << "Caught exception" << std::endl; | |
| 4244 | ✗ | return false; | |
| 4245 | ✗ | } | |
| 4246 | |||
| 4247 | ✗ | M.facets.connect(); | |
| 4248 | |||
| 4249 | ✗ | return true; | |
| 4250 | ✗ | } | |
| 4251 | |||
| 4252 | /** | ||
| 4253 | * \copydoc MeshIOHandler::save() | ||
| 4254 | */ | ||
| 4255 | ✗ | bool save( | |
| 4256 | const Mesh& M, const std::string& filename, | ||
| 4257 | const MeshIOFlags& ioflags = MeshIOFlags() | ||
| 4258 | ) override { | ||
| 4259 | ✗ | geo_argused(ioflags); | |
| 4260 | |||
| 4261 | ✗ | Attribute<int> vertex_id; | |
| 4262 | ✗ | vertex_id.bind_if_is_defined(M.vertices.attributes(), "vertex_id"); | |
| 4263 | ✗ | Attribute<int> cell_id; | |
| 4264 | ✗ | cell_id.bind_if_is_defined(M.facets.attributes(), "cell_id"); | |
| 4265 | |||
| 4266 | ✗ | if(!vertex_id.is_bound()) { | |
| 4267 | ✗ | Logger::err("OVM") << "Missing vertex ids" << std::endl; | |
| 4268 | ✗ | return false; | |
| 4269 | } | ||
| 4270 | |||
| 4271 | ✗ | if(!cell_id.is_bound()) { | |
| 4272 | ✗ | Logger::err("OVM") << "Missing cell ids" << std::endl; | |
| 4273 | ✗ | return false; | |
| 4274 | } | ||
| 4275 | |||
| 4276 | ✗ | std::ofstream out(filename.c_str()); | |
| 4277 | ✗ | if(!out) { | |
| 4278 | ✗ | return false; | |
| 4279 | } | ||
| 4280 | |||
| 4281 | ✗ | out << "OVM ASCII" << std::endl; | |
| 4282 | |||
| 4283 | // Output the vertices | ||
| 4284 | { | ||
| 4285 | ✗ | index_t nb_vertices = 0; | |
| 4286 | ✗ | FOR(v, M.vertices.nb()) { | |
| 4287 | ✗ | nb_vertices = std::max(nb_vertices, index_t(vertex_id[v])); | |
| 4288 | } | ||
| 4289 | ✗ | ++nb_vertices; | |
| 4290 | ✗ | vector<index_t> vid_to_v(nb_vertices); | |
| 4291 | ✗ | FOR(v, M.vertices.nb()) { | |
| 4292 | ✗ | vid_to_v[vertex_id[v]] = v; | |
| 4293 | } | ||
| 4294 | ✗ | out << "Vertices" << std::endl; | |
| 4295 | ✗ | out << nb_vertices << std::endl; | |
| 4296 | ✗ | FOR(vid, nb_vertices) { | |
| 4297 | ✗ | const double* p = M.vertices.point_ptr(vid_to_v[vid]); | |
| 4298 | ✗ | FOR(d, M.vertices.dimension()) { | |
| 4299 | ✗ | out << std::setprecision(17) << p[d] << " "; | |
| 4300 | } | ||
| 4301 | ✗ | out << std::endl; | |
| 4302 | } | ||
| 4303 | ✗ | } | |
| 4304 | |||
| 4305 | ✗ | std::map<bindex, index_t> edge_to_id; | |
| 4306 | ✗ | vector<bindex> edges; | |
| 4307 | ✗ | index_t nb_edges = 0; | |
| 4308 | |||
| 4309 | // Construct edge table and output edges | ||
| 4310 | { | ||
| 4311 | ✗ | FOR(f, M.facets.nb()) { | |
| 4312 | ✗ | for( | |
| 4313 | ✗ | index_t c1=M.facets.corners_begin(f); | |
| 4314 | ✗ | c1<M.facets.corners_end(f); ++c1 | |
| 4315 | ) { | ||
| 4316 | ✗ | index_t c2 = M.facets.next_corner_around_facet(f,c1); | |
| 4317 | index_t iv1 = | ||
| 4318 | ✗ | index_t(vertex_id[M.facet_corners.vertex(c1)]); | |
| 4319 | index_t iv2 = | ||
| 4320 | ✗ | index_t(vertex_id[M.facet_corners.vertex(c2)]); | |
| 4321 | ✗ | bindex K(iv1, iv2); | |
| 4322 | ✗ | if(edge_to_id.find(K) == edge_to_id.end()) { | |
| 4323 | ✗ | edge_to_id[K] = nb_edges; | |
| 4324 | ✗ | edges.push_back(K); | |
| 4325 | ✗ | ++nb_edges; | |
| 4326 | } | ||
| 4327 | } | ||
| 4328 | } | ||
| 4329 | ✗ | out << "Edges" << std::endl; | |
| 4330 | ✗ | out << nb_edges << std::endl; | |
| 4331 | ✗ | FOR(e, nb_edges) { | |
| 4332 | ✗ | out << edges[e].indices[0] << " " | |
| 4333 | ✗ | << edges[e].indices[1] << std::endl; | |
| 4334 | } | ||
| 4335 | } | ||
| 4336 | |||
| 4337 | ✗ | std::map<trindex, index_t> facet_to_id; | |
| 4338 | ✗ | vector<index_t> facets; | |
| 4339 | ✗ | index_t nb_facets = 0; | |
| 4340 | |||
| 4341 | // Construct facet table and output facets | ||
| 4342 | { | ||
| 4343 | ✗ | FOR(f, M.facets.nb()) { | |
| 4344 | ✗ | trindex K = facet_key(M, f, vertex_id, false); | |
| 4345 | ✗ | trindex Kinv = facet_key(M, f, vertex_id, true); | |
| 4346 | ✗ | if( | |
| 4347 | ✗ | facet_to_id.find(K) == facet_to_id.end() && | |
| 4348 | ✗ | facet_to_id.find(Kinv) == facet_to_id.end() | |
| 4349 | ) { | ||
| 4350 | ✗ | facet_to_id[K] = 2*nb_facets; | |
| 4351 | ✗ | facet_to_id[Kinv] = 2*nb_facets + 1; | |
| 4352 | ✗ | ++nb_facets; | |
| 4353 | ✗ | facets.push_back(f); | |
| 4354 | } | ||
| 4355 | } | ||
| 4356 | ✗ | out << "Faces" << std::endl; | |
| 4357 | ✗ | out << nb_facets << std::endl; | |
| 4358 | ✗ | FOR(fi, nb_facets) { | |
| 4359 | ✗ | index_t f = facets[fi]; | |
| 4360 | ✗ | out << M.facets.nb_vertices(f) << " "; | |
| 4361 | ✗ | for( | |
| 4362 | ✗ | index_t c1=M.facets.corners_begin(f); | |
| 4363 | ✗ | c1<M.facets.corners_end(f); ++c1 | |
| 4364 | ) { | ||
| 4365 | ✗ | index_t c2 = M.facets.next_corner_around_facet(f,c1); | |
| 4366 | index_t iv1 = | ||
| 4367 | ✗ | index_t(vertex_id[M.facet_corners.vertex(c1)]); | |
| 4368 | index_t iv2 = | ||
| 4369 | ✗ | index_t(vertex_id[M.facet_corners.vertex(c2)]); | |
| 4370 | ✗ | bindex K(iv1, iv2, bindex::KEEP_ORDER); | |
| 4371 | ✗ | index_t ie = NO_INDEX; | |
| 4372 | ✗ | auto it = edge_to_id.find(K); | |
| 4373 | ✗ | if(it == edge_to_id.end()) { | |
| 4374 | ✗ | ie = 2*edge_to_id[bindex(iv1,iv2)]+1; | |
| 4375 | } else { | ||
| 4376 | ✗ | ie = 2*it->second; | |
| 4377 | } | ||
| 4378 | ✗ | out << ie << " "; | |
| 4379 | } | ||
| 4380 | ✗ | out << std::endl; | |
| 4381 | } | ||
| 4382 | } | ||
| 4383 | |||
| 4384 | // Construct cell table and output cells | ||
| 4385 | |||
| 4386 | ✗ | index_t nb_cells = 0; | |
| 4387 | ✗ | FOR(f, M.facets.nb()) { | |
| 4388 | ✗ | nb_cells = std::max(nb_cells, index_t(cell_id[f])); | |
| 4389 | } | ||
| 4390 | ✗ | ++nb_cells; | |
| 4391 | |||
| 4392 | // Ugly ! One could use compressed row storage instead. | ||
| 4393 | // ... but anyway we got all these tables indexed by bindexes | ||
| 4394 | // and trindexes that eat much memory, no need to optimize that | ||
| 4395 | // for now since tables storage probably dominate... | ||
| 4396 | ✗ | vector< vector<index_t> >cell_to_f(nb_cells); | |
| 4397 | ✗ | FOR(f, M.facets.nb()) { | |
| 4398 | ✗ | cell_to_f[cell_id[f]].push_back(f); | |
| 4399 | } | ||
| 4400 | |||
| 4401 | ✗ | out << "Polyhedra" << std::endl; | |
| 4402 | ✗ | out << nb_cells << std::endl; | |
| 4403 | |||
| 4404 | ✗ | FOR(ci, nb_cells) { | |
| 4405 | ✗ | out << cell_to_f[ci].size() << " "; | |
| 4406 | ✗ | FOR(lf, cell_to_f[ci].size()) { | |
| 4407 | ✗ | index_t f = cell_to_f[ci][lf]; | |
| 4408 | ✗ | trindex K = facet_key(M, f, vertex_id); | |
| 4409 | ✗ | out << facet_to_id[K] << " "; | |
| 4410 | } | ||
| 4411 | ✗ | out << std::endl; | |
| 4412 | } | ||
| 4413 | |||
| 4414 | ✗ | vertex_id.unbind(); | |
| 4415 | ✗ | cell_id.unbind(); | |
| 4416 | |||
| 4417 | ✗ | return true; | |
| 4418 | ✗ | } | |
| 4419 | |||
| 4420 | private: | ||
| 4421 | |||
| 4422 | /** | ||
| 4423 | * \brief Gets one keyword from the next line. | ||
| 4424 | * \param[in] in a reference to the line input stream. | ||
| 4425 | * \details Throws an exception if the line has | ||
| 4426 | * not exactly one keyword. | ||
| 4427 | */ | ||
| 4428 | ✗ | std::string get_keyword(LineInput& in) { | |
| 4429 | ✗ | in.get_line(); | |
| 4430 | ✗ | in.get_fields(); | |
| 4431 | ✗ | if(in.nb_fields() == 0 && in.eof()) { | |
| 4432 | ✗ | return std::string(""); | |
| 4433 | } | ||
| 4434 | ✗ | if(in.nb_fields() < 1) { | |
| 4435 | ✗ | throw("Expected one keyword"); | |
| 4436 | } | ||
| 4437 | ✗ | return std::string(in.field(0)); | |
| 4438 | } | ||
| 4439 | |||
| 4440 | /** | ||
| 4441 | * \brief Gets one unsigned integer from the next | ||
| 4442 | * line. | ||
| 4443 | * \param[in] in a reference to the line input stream. | ||
| 4444 | * \details Throws an exception if the next line | ||
| 4445 | * has not exactly one unsigned integer. | ||
| 4446 | */ | ||
| 4447 | ✗ | index_t get_number(LineInput& in) { | |
| 4448 | ✗ | in.get_line(); | |
| 4449 | ✗ | in.get_fields(); | |
| 4450 | ✗ | if(in.nb_fields() != 1) { | |
| 4451 | ✗ | throw("Expected one number"); | |
| 4452 | } | ||
| 4453 | ✗ | index_t result = in.field_as_uint(0); | |
| 4454 | ✗ | return result; | |
| 4455 | } | ||
| 4456 | |||
| 4457 | /* | ||
| 4458 | * \brief Skips property. | ||
| 4459 | * \param[in] in a reference to the line input stream. | ||
| 4460 | * \param[in] nb_elements number of elements to be skipped | ||
| 4461 | */ | ||
| 4462 | ✗ | void skip_property(LineInput& in, index_t nb_elements) { | |
| 4463 | // +1 because there is the type of the property | ||
| 4464 | ✗ | FOR(i, nb_elements+1) { | |
| 4465 | ✗ | in.get_line(); | |
| 4466 | } | ||
| 4467 | ✗ | } | |
| 4468 | |||
| 4469 | /** | ||
| 4470 | * \brief Gets a key to be able to retrieve facet indices. | ||
| 4471 | * \param[in] M a reference to a mesh | ||
| 4472 | * \param[in] f a facet of the mesh | ||
| 4473 | * \param[in] vertex_id an Id attribute attached to the vertices | ||
| 4474 | * \param[in] invert if true, invert the order of the vertices | ||
| 4475 | * of the facet. | ||
| 4476 | * \return a trindex composed of the ids of three corners of the | ||
| 4477 | * facet, formed by the id of the vertex with the lowest id, | ||
| 4478 | * and the ids of its predecessor and successor around the facet. | ||
| 4479 | */ | ||
| 4480 | |||
| 4481 | ✗ | static trindex facet_key( | |
| 4482 | const Mesh& M, index_t f, const Attribute<int>& vertex_id, | ||
| 4483 | bool invert=false | ||
| 4484 | ) { | ||
| 4485 | ✗ | index_t min_iv = NO_INDEX; | |
| 4486 | ✗ | index_t min_corner = NO_INDEX; | |
| 4487 | ✗ | for( | |
| 4488 | ✗ | index_t c=M.facets.corners_begin(f); | |
| 4489 | ✗ | c<M.facets.corners_end(f); ++c | |
| 4490 | ) { | ||
| 4491 | ✗ | index_t iv = index_t(vertex_id[M.facet_corners.vertex(c)]); | |
| 4492 | ✗ | if(min_iv == NO_INDEX || iv < min_iv) { | |
| 4493 | ✗ | min_corner = c; | |
| 4494 | ✗ | min_iv = iv; | |
| 4495 | } | ||
| 4496 | } | ||
| 4497 | ✗ | index_t c1 = min_corner; | |
| 4498 | ✗ | index_t c2 = invert ? | |
| 4499 | ✗ | M.facets.prev_corner_around_facet(f,c1) : | |
| 4500 | ✗ | M.facets.next_corner_around_facet(f,c1) ; | |
| 4501 | ✗ | index_t c3 = invert ? | |
| 4502 | ✗ | M.facets.prev_corner_around_facet(f,c2) : | |
| 4503 | ✗ | M.facets.next_corner_around_facet(f,c2) ; | |
| 4504 | ✗ | index_t iv1 = index_t(vertex_id[M.facet_corners.vertex(c1)]); | |
| 4505 | ✗ | index_t iv2 = index_t(vertex_id[M.facet_corners.vertex(c2)]); | |
| 4506 | ✗ | index_t iv3 = index_t(vertex_id[M.facet_corners.vertex(c3)]); | |
| 4507 | ✗ | return trindex(iv1,iv2,iv3,trindex::KEEP_ORDER); | |
| 4508 | } | ||
| 4509 | |||
| 4510 | }; | ||
| 4511 | |||
| 4512 | /****************************************************************************/ | ||
| 4513 | |||
| 4514 | const index_t id_offset_msh = 1; | ||
| 4515 | const index_t msh2geo_hex[8] = {1, 3, 7, 5, 0, 2, 6, 4 }; | ||
| 4516 | const index_t msh2geo_def[8] = {0, 1, 2, 3, 4, 5, 6, 7 }; | ||
| 4517 | const index_t celltype_geo2msh[5] = {4, 5, 6, 7}; | ||
| 4518 | |||
| 4519 | /** | ||
| 4520 | * \brief Support for GMSH file format. | ||
| 4521 | * \details By Maxence Reberol. | ||
| 4522 | */ | ||
| 4523 | class GEOGRAM_API MSHIOHandler : public MeshIOHandler { | ||
| 4524 | public: | ||
| 4525 | ✗ | MSHIOHandler() { | |
| 4526 | ✗ | } | |
| 4527 | |||
| 4528 | ✗ | bool verify_file_format(const std::string& filename) { | |
| 4529 | ✗ | LineInput in(filename); | |
| 4530 | ✗ | if (!in.OK()) return false; | |
| 4531 | ✗ | in.get_line(); | |
| 4532 | ✗ | in.get_fields(); | |
| 4533 | ✗ | if (in.field_matches(0, "$MeshFormat")) { | |
| 4534 | ✗ | in.get_line(); | |
| 4535 | ✗ | in.get_fields(); | |
| 4536 | ✗ | if (in.field_as_double(0) == 2.2 | |
| 4537 | ✗ | && in.field_as_uint(1) == 0 | |
| 4538 | ✗ | && in.field_as_uint(2) == 8 | |
| 4539 | ✗ | ) return true; | |
| 4540 | } | ||
| 4541 | ✗ | return false; | |
| 4542 | ✗ | } | |
| 4543 | |||
| 4544 | ✗ | bool read_vertices(const std::string& filename, Mesh& M) { | |
| 4545 | ✗ | LineInput in(filename); | |
| 4546 | ✗ | while (in.get_line()) { | |
| 4547 | ✗ | in.get_fields(); | |
| 4548 | ✗ | if (in.field_matches(0, "$Nodes")) { | |
| 4549 | ✗ | in.get_line(); | |
| 4550 | ✗ | in.get_fields(); | |
| 4551 | ✗ | geo_assert(in.nb_fields() == 1); | |
| 4552 | ✗ | M.vertices.create_vertices(in.field_as_uint(0)); | |
| 4553 | ✗ | for (index_t v = 0; v < M.vertices.nb(); ++v){ | |
| 4554 | ✗ | in.get_line(); | |
| 4555 | ✗ | in.get_fields(); | |
| 4556 | ✗ | geo_assert(in.nb_fields() == 4); | |
| 4557 | ✗ | double pt[4] = { | |
| 4558 | ✗ | in.field_as_double(1), | |
| 4559 | ✗ | in.field_as_double(2), | |
| 4560 | ✗ | in.field_as_double(3) | |
| 4561 | ✗ | }; | |
| 4562 | ✗ | set_mesh_point(M, v, pt, 3); | |
| 4563 | } | ||
| 4564 | ✗ | } else if (in.field_matches(0, "$EndNodes")) { | |
| 4565 | ✗ | return true; | |
| 4566 | } | ||
| 4567 | } | ||
| 4568 | ✗ | return false; | |
| 4569 | ✗ | } | |
| 4570 | ✗ | bool read_elements(const std::string& filename, Mesh& M) { | |
| 4571 | ✗ | index_t nb_elements = 0; | |
| 4572 | ✗ | index_t nb_edges = 0; | |
| 4573 | ✗ | index_t nb_tri = 0; | |
| 4574 | ✗ | index_t nb_quad = 0; | |
| 4575 | ✗ | index_t nb_tet = 0; | |
| 4576 | ✗ | index_t nb_hex = 0; | |
| 4577 | ✗ | index_t nb_pyr = 0; | |
| 4578 | ✗ | index_t nb_pri = 0; | |
| 4579 | ✗ | index_t nb_oth = 0; | |
| 4580 | { /* First pass to get the number of each element type */ | ||
| 4581 | ✗ | LineInput in(filename); | |
| 4582 | ✗ | while (in.get_line()) { | |
| 4583 | ✗ | in.get_fields(); | |
| 4584 | ✗ | if (in.field_matches(0, "$Elements")) { | |
| 4585 | ✗ | in.get_line(); | |
| 4586 | ✗ | in.get_fields(); | |
| 4587 | ✗ | geo_assert(in.nb_fields() == 1); | |
| 4588 | ✗ | nb_elements = in.field_as_uint(0); | |
| 4589 | ✗ | for (index_t e = 0; e < nb_elements; ++e){ | |
| 4590 | ✗ | in.get_line(); | |
| 4591 | ✗ | in.get_fields(); | |
| 4592 | ✗ | if (in.field_as_uint(1) == 1) nb_edges += 1; | |
| 4593 | ✗ | else if (in.field_as_uint(1) == 2) nb_tri += 1; | |
| 4594 | ✗ | else if (in.field_as_uint(1) == 3) nb_quad += 1; | |
| 4595 | ✗ | else if (in.field_as_uint(1) == 4) nb_tet += 1; | |
| 4596 | ✗ | else if (in.field_as_uint(1) == 5) nb_hex += 1; | |
| 4597 | ✗ | else if (in.field_as_uint(1) == 6) nb_pri += 1; | |
| 4598 | ✗ | else if (in.field_as_uint(1) == 7) nb_pyr += 1; | |
| 4599 | ✗ | else { nb_oth += 1; } | |
| 4600 | } | ||
| 4601 | ✗ | if (nb_oth > 0) { | |
| 4602 | ✗ | Logger::warn("I/O") | |
| 4603 | ✗ | << nb_oth | |
| 4604 | ✗ | << " elements with type unsupported" | |
| 4605 | ✗ | << std::endl; | |
| 4606 | } | ||
| 4607 | } | ||
| 4608 | } | ||
| 4609 | ✗ | M.edges.create_edges(nb_edges); | |
| 4610 | ✗ | M.facets.create_triangles(nb_tri); | |
| 4611 | ✗ | M.facets.create_quads(nb_quad); | |
| 4612 | ✗ | M.cells.create_tets(nb_tet); | |
| 4613 | ✗ | M.cells.create_hexes(nb_hex); | |
| 4614 | ✗ | M.cells.create_pyramids(nb_pyr); | |
| 4615 | ✗ | M.cells.create_prisms(nb_pri); | |
| 4616 | ✗ | } | |
| 4617 | { /* Second pass to fill the content of the mesh */ | ||
| 4618 | /* Re-use the number of elts as counters */ | ||
| 4619 | ✗ | nb_edges = 0; | |
| 4620 | ✗ | index_t nb_facets = 0; | |
| 4621 | ✗ | index_t nb_cells = 0; | |
| 4622 | ✗ | LineInput in(filename); | |
| 4623 | ✗ | while (in.get_line()) { | |
| 4624 | ✗ | in.get_fields(); | |
| 4625 | ✗ | if (in.field_matches(0, "$Elements")) { | |
| 4626 | ✗ | in.get_line(); | |
| 4627 | ✗ | in.get_fields(); | |
| 4628 | ✗ | geo_assert(in.field_as_uint(0) == nb_elements); | |
| 4629 | ✗ | for (index_t e = 0; e < nb_elements; ++e){ | |
| 4630 | ✗ | in.get_line(); | |
| 4631 | ✗ | in.get_fields(); | |
| 4632 | ✗ | index_t nb_tags = in.field_as_uint(2); | |
| 4633 | ✗ | index_t offset = 3 + nb_tags; | |
| 4634 | ✗ | if (in.field_as_uint(1) == 1) { | |
| 4635 | ✗ | index_t nbv = 2; | |
| 4636 | ✗ | geo_debug_assert( | |
| 4637 | in.nb_fields() == offset + nbv | ||
| 4638 | ); | ||
| 4639 | ✗ | for (index_t j = 0; j < nbv; ++j) { | |
| 4640 | ✗ | M.edges.set_vertex( | |
| 4641 | nb_edges, j, | ||
| 4642 | ✗ | in.field_as_uint(offset + j) - 1 | |
| 4643 | ); | ||
| 4644 | } | ||
| 4645 | ✗ | nb_edges += 1; | |
| 4646 | ✗ | } else if (in.field_as_uint(1) == 2) { | |
| 4647 | ✗ | index_t nbv = 3; | |
| 4648 | ✗ | geo_debug_assert( | |
| 4649 | in.nb_fields() == offset + nbv | ||
| 4650 | ); | ||
| 4651 | ✗ | for (index_t j = 0; j < nbv; ++j) { | |
| 4652 | ✗ | M.facets.set_vertex( | |
| 4653 | nb_facets, j, | ||
| 4654 | ✗ | in.field_as_uint(offset + j) - 1 | |
| 4655 | ); | ||
| 4656 | } | ||
| 4657 | ✗ | nb_facets += 1; | |
| 4658 | ✗ | } else if (in.field_as_uint(1) == 3) { | |
| 4659 | ✗ | index_t nbv = 4; | |
| 4660 | ✗ | geo_debug_assert( | |
| 4661 | in.nb_fields() == offset + nbv | ||
| 4662 | ); | ||
| 4663 | ✗ | for (index_t j = 0; j < nbv; ++j) { | |
| 4664 | ✗ | M.facets.set_vertex( | |
| 4665 | nb_facets, j, | ||
| 4666 | ✗ | in.field_as_uint(offset + j) - 1 | |
| 4667 | ); | ||
| 4668 | } | ||
| 4669 | ✗ | nb_facets += 1; | |
| 4670 | ✗ | } else if (in.field_as_uint(1) == 4) { | |
| 4671 | ✗ | index_t nbv = 4; | |
| 4672 | ✗ | geo_debug_assert( | |
| 4673 | in.nb_fields() == offset + nbv | ||
| 4674 | ); | ||
| 4675 | ✗ | for (index_t j = 0; j < nbv; ++j) { | |
| 4676 | ✗ | M.cells.set_vertex( | |
| 4677 | nb_cells, j, | ||
| 4678 | ✗ | in.field_as_uint(offset + j) - 1 | |
| 4679 | ); | ||
| 4680 | } | ||
| 4681 | ✗ | nb_cells += 1; | |
| 4682 | ✗ | } else if (in.field_as_uint(1) == 5) { | |
| 4683 | ✗ | index_t nbv = 8; | |
| 4684 | ✗ | geo_debug_assert( | |
| 4685 | in.nb_fields() == offset + nbv | ||
| 4686 | ); | ||
| 4687 | ✗ | for (index_t j = 0; j < nbv; ++j) { | |
| 4688 | ✗ | M.cells.set_vertex( | |
| 4689 | ✗ | nb_cells, msh2geo_hex[j], | |
| 4690 | ✗ | in.field_as_uint(offset + j) - 1 | |
| 4691 | ); | ||
| 4692 | } | ||
| 4693 | ✗ | nb_cells += 1; | |
| 4694 | ✗ | } else if (in.field_as_uint(1) == 6) { | |
| 4695 | ✗ | index_t nbv = 6; | |
| 4696 | ✗ | geo_debug_assert( | |
| 4697 | in.nb_fields() == offset + nbv | ||
| 4698 | ); | ||
| 4699 | ✗ | for (index_t j = 0; j < nbv; ++j) { | |
| 4700 | ✗ | M.cells.set_vertex( | |
| 4701 | nb_cells, j, | ||
| 4702 | ✗ | in.field_as_uint(offset + j) - 1 | |
| 4703 | ); | ||
| 4704 | } | ||
| 4705 | ✗ | nb_cells += 1; | |
| 4706 | ✗ | } else if (in.field_as_uint(1) == 7) { | |
| 4707 | ✗ | index_t nbv = 5; | |
| 4708 | ✗ | geo_debug_assert( | |
| 4709 | in.nb_fields() == offset + nbv | ||
| 4710 | ); | ||
| 4711 | ✗ | for (index_t j = 0; j < nbv; ++j) { | |
| 4712 | ✗ | M.cells.set_vertex( | |
| 4713 | nb_cells, j, | ||
| 4714 | ✗ | in.field_as_uint(offset + j) - 1 | |
| 4715 | ); | ||
| 4716 | } | ||
| 4717 | ✗ | nb_cells += 1; | |
| 4718 | } | ||
| 4719 | } | ||
| 4720 | } | ||
| 4721 | } | ||
| 4722 | ✗ | } | |
| 4723 | ✗ | return true; | |
| 4724 | } | ||
| 4725 | |||
| 4726 | ✗ | bool load( | |
| 4727 | const std::string& filename, Mesh& M, | ||
| 4728 | const MeshIOFlags& ioflags | ||
| 4729 | ) override { | ||
| 4730 | ✗ | geo_argused(ioflags); | |
| 4731 | ✗ | M.clear(); | |
| 4732 | ✗ | M.vertices.set_dimension(3); | |
| 4733 | try { | ||
| 4734 | ✗ | if (!verify_file_format(filename)) { | |
| 4735 | ✗ | Logger::err("I/O") | |
| 4736 | ✗ | << "$MeshFormat not supported" << std::endl; | |
| 4737 | ✗ | return false; | |
| 4738 | } | ||
| 4739 | ✗ | if (!read_vertices(filename, M)) { | |
| 4740 | ✗ | Logger::err("I/O") | |
| 4741 | ✗ | << "failed to read vertices" << std::endl; | |
| 4742 | ✗ | return false; | |
| 4743 | } | ||
| 4744 | ✗ | if (!read_elements(filename, M)) { | |
| 4745 | ✗ | Logger::err("I/O") | |
| 4746 | ✗ | << "failed to read elements" << std::endl; | |
| 4747 | ✗ | return false; | |
| 4748 | } | ||
| 4749 | ✗ | } catch(const std::string& what) { | |
| 4750 | ✗ | Logger::err("I/O") << what << std::endl; | |
| 4751 | ✗ | return false; | |
| 4752 | ✗ | } catch(const std::exception& ex) { | |
| 4753 | ✗ | Logger::err("I/O") << ex.what() << std::endl; | |
| 4754 | ✗ | return false; | |
| 4755 | ✗ | } catch(...) { | |
| 4756 | ✗ | Logger::err("I/O") << "Caught exception" << std::endl; | |
| 4757 | ✗ | return false; | |
| 4758 | ✗ | } | |
| 4759 | ✗ | return true; | |
| 4760 | } | ||
| 4761 | |||
| 4762 | ✗ | bool save( | |
| 4763 | const Mesh& M_in, const std::string& filename, | ||
| 4764 | const MeshIOFlags& ioflags | ||
| 4765 | ) override { | ||
| 4766 | |||
| 4767 | ✗ | Mesh M(M_in.vertices.dimension()); | |
| 4768 | ✗ | M.copy(M_in, true); | |
| 4769 | |||
| 4770 | ✗ | M.vertices.remove_isolated(); | |
| 4771 | |||
| 4772 | ✗ | Attribute<index_t> region; | |
| 4773 | ✗ | Attribute<index_t> bdr_region; | |
| 4774 | ✗ | if (M.cells.attributes().is_defined("region")) { | |
| 4775 | ✗ | region.bind(M.cells.attributes(), "region"); | |
| 4776 | } | ||
| 4777 | ✗ | if (M.facets.attributes().is_defined("bdr_region")) { | |
| 4778 | ✗ | bdr_region.bind(M.facets.attributes(), "bdr_region"); | |
| 4779 | } | ||
| 4780 | |||
| 4781 | ✗ | std::ofstream out( filename.c_str() ) ; | |
| 4782 | |||
| 4783 | ✗ | if( !out ) { | |
| 4784 | ✗ | Logger::err("I/O") << "Fail to open \"" << filename << "\" for writing" << std::endl; | |
| 4785 | ✗ | return false; | |
| 4786 | } | ||
| 4787 | |||
| 4788 | ✗ | out.precision( 16 ) ; | |
| 4789 | |||
| 4790 | /* Header */ | ||
| 4791 | ✗ | out << "$MeshFormat\n"; | |
| 4792 | ✗ | out << "2.2 0 " << sizeof(double) << std::endl; | |
| 4793 | ✗ | out << "$EndMeshFormat\n"; | |
| 4794 | |||
| 4795 | /* Vertices */ | ||
| 4796 | ✗ | out << "$Nodes" << std::endl ; | |
| 4797 | ✗ | out << M.vertices.nb() << std::endl ; | |
| 4798 | ✗ | for( index_t v = 0; v < M.vertices.nb(); v++ ) { | |
| 4799 | ✗ | out << v + id_offset_msh << " " | |
| 4800 | ✗ | << M.vertices.point_ptr(v)[0] << " " | |
| 4801 | ✗ | << M.vertices.point_ptr(v)[1] << " " | |
| 4802 | ✗ | << M.vertices.point_ptr(v)[2] << '\n' ; | |
| 4803 | } | ||
| 4804 | ✗ | out << "$EndNodes" << std::endl ; | |
| 4805 | |||
| 4806 | /* Elements */ | ||
| 4807 | ✗ | index_t nb_tet = 0; | |
| 4808 | ✗ | index_t nb_hex = 0; | |
| 4809 | ✗ | index_t nb_pyr = 0; | |
| 4810 | ✗ | index_t nb_pri = 0; | |
| 4811 | ✗ | for(index_t c = 0; c != M.cells.nb(); ++c){ | |
| 4812 | ✗ | if(M.cells.type(c) == GEO::MESH_TET){ | |
| 4813 | ✗ | ++nb_tet; | |
| 4814 | ✗ | } else if(M.cells.type(c) == GEO::MESH_HEX){ | |
| 4815 | ✗ | ++nb_hex; | |
| 4816 | ✗ | } else if(M.cells.type(c) == GEO::MESH_PYRAMID){ | |
| 4817 | ✗ | ++nb_pyr; | |
| 4818 | ✗ | } else if(M.cells.type(c) == GEO::MESH_PRISM){ | |
| 4819 | ✗ | ++nb_pri; | |
| 4820 | } | ||
| 4821 | } | ||
| 4822 | ✗ | index_t nb_elt = nb_tet + nb_hex + nb_pyr + nb_pri; | |
| 4823 | ✗ | if (ioflags.has_element(MESH_FACETS)) nb_elt += M.facets.nb(); | |
| 4824 | |||
| 4825 | ✗ | out << "$Elements" << std::endl ; | |
| 4826 | ✗ | out << nb_elt << std::endl ; | |
| 4827 | ✗ | index_t elt_id = 0; /* starts at 1, common for faces and cells */ | |
| 4828 | ✗ | if (ioflags.has_element(MESH_FACETS)) { | |
| 4829 | ✗ | for (index_t f = 0; f < M.facets.nb(); ++f) { | |
| 4830 | ✗ | int attr_value = 0; | |
| 4831 | ✗ | if (bdr_region.is_bound()){ | |
| 4832 | ✗ | attr_value = int(bdr_region[f]); | |
| 4833 | } | ||
| 4834 | ✗ | int type = -1; | |
| 4835 | ✗ | if (M.facets.nb_vertices(f) == 3) { | |
| 4836 | ✗ | type = 2; | |
| 4837 | ✗ | } else if (M.facets.nb_vertices(f) == 4) { | |
| 4838 | ✗ | type = 3; | |
| 4839 | } else { | ||
| 4840 | ✗ | geo_assert_not_reached | |
| 4841 | } | ||
| 4842 | ✗ | elt_id += 1; | |
| 4843 | ✗ | out << elt_id << " " << type << " " << "2" << " " | |
| 4844 | ✗ | << attr_value << " " << attr_value << " "; | |
| 4845 | ✗ | for (index_t li = 0; li < M.facets.nb_vertices(f); ++li) { | |
| 4846 | ✗ | out << M.facets.vertex(f, li) + id_offset_msh << " "; | |
| 4847 | } | ||
| 4848 | ✗ | out << std::endl; | |
| 4849 | } | ||
| 4850 | } | ||
| 4851 | ✗ | for (index_t c = 0; c < M.cells.nb(); ++c) { | |
| 4852 | ✗ | if (M.cells.type(c) == GEO::MESH_CONNECTOR) { | |
| 4853 | ✗ | continue; | |
| 4854 | } | ||
| 4855 | ✗ | int attr_value = 0; | |
| 4856 | ✗ | if (region.is_bound()) { | |
| 4857 | ✗ | attr_value = int(region[c]); | |
| 4858 | } | ||
| 4859 | const index_t* msh2geo = | ||
| 4860 | ✗ | (M.cells.type(c) == GEO::MESH_HEX) ? | |
| 4861 | ✗ | msh2geo_hex : msh2geo_def; | |
| 4862 | ✗ | elt_id += 1; | |
| 4863 | |||
| 4864 | /* Write to file, format is: | ||
| 4865 | * elm-number elm-type number-of-tags < tag > ... | ||
| 4866 | * node-number-list | ||
| 4867 | */ | ||
| 4868 | ✗ | out << elt_id << " " << celltype_geo2msh[M.cells.type(c)] | |
| 4869 | ✗ | << " " << "1" << " " << attr_value << " "; | |
| 4870 | ✗ | for (index_t li = 0; li < M.cells.nb_vertices(c); ++li) { | |
| 4871 | ✗ | out << M.cells.vertex(c, msh2geo[li]) + id_offset_msh | |
| 4872 | ✗ | << " "; | |
| 4873 | } | ||
| 4874 | ✗ | out << std::endl; | |
| 4875 | } | ||
| 4876 | ✗ | out << "$EndElements" << std::endl; | |
| 4877 | |||
| 4878 | ✗ | out.close(); | |
| 4879 | ✗ | return true; | |
| 4880 | ✗ | } | |
| 4881 | }; | ||
| 4882 | |||
| 4883 | } | ||
| 4884 | |||
| 4885 | /****************************************************************************/ | ||
| 4886 | |||
| 4887 | namespace GEO { | ||
| 4888 | |||
| 4889 | 421 | MeshIOFlags::MeshIOFlags() { | |
| 4890 | 421 | dimension_ = 3; | |
| 4891 | 421 | attributes_ = MESH_NO_ATTRIBUTES; | |
| 4892 | 421 | elements_ = MESH_ALL_ELEMENTS; | |
| 4893 | 421 | verbose_ = true; | |
| 4894 | 421 | } | |
| 4895 | |||
| 4896 | /************************************************************************/ | ||
| 4897 | |||
| 4898 | 271 | bool GEOGRAM_API mesh_load( | |
| 4899 | const std::string& filename, Mesh& M, | ||
| 4900 | const MeshIOFlags& ioflags | ||
| 4901 | ) { | ||
| 4902 |
1/2✓ Branch 1 taken 271 times.
✗ Branch 2 not taken.
|
271 | if(ioflags.verbose()) { |
| 4903 |
2/4✓ Branch 1 taken 271 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 271 times.
✗ Branch 5 not taken.
|
813 | Logger::out("I/O") |
| 4904 |
3/6✓ Branch 1 taken 271 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 271 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 271 times.
✗ Branch 8 not taken.
|
271 | << "Loading file " << filename << "..." |
| 4905 |
1/2✓ Branch 1 taken 271 times.
✗ Branch 2 not taken.
|
271 | << std::endl; |
| 4906 | } | ||
| 4907 | |||
| 4908 |
1/2✓ Branch 1 taken 271 times.
✗ Branch 2 not taken.
|
271 | M.clear(); |
| 4909 | |||
| 4910 | 271 | bool result = false; | |
| 4911 |
1/2✓ Branch 1 taken 271 times.
✗ Branch 2 not taken.
|
271 | MeshIOHandler_var handler = MeshIOHandler::get_handler(filename); |
| 4912 |
2/2✓ Branch 1 taken 270 times.
✓ Branch 2 taken 1 times.
|
271 | if(handler != nullptr) { |
| 4913 | try { | ||
| 4914 |
3/4✓ Branch 1 taken 270 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 265 times.
✓ Branch 5 taken 5 times.
|
270 | result = handler->load(filename, M, ioflags); |
| 4915 | } | ||
| 4916 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
|
5 | catch(const std::exception& ex) { |
| 4917 |
4/8✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 5 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 5 times.
✗ Branch 12 not taken.
|
5 | Logger::err("I/O") << ex.what() << std::endl; |
| 4918 | 5 | result = false; | |
| 4919 | 5 | } | |
| 4920 | } | ||
| 4921 | |||
| 4922 |
2/2✓ Branch 0 taken 19 times.
✓ Branch 1 taken 252 times.
|
271 | if(!result) { |
| 4923 |
2/4✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 19 times.
✗ Branch 5 not taken.
|
38 | Logger::err("I/O") |
| 4924 |
2/4✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 19 times.
✗ Branch 5 not taken.
|
19 | << "Could not load file: " << filename |
| 4925 |
1/2✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
|
19 | << std::endl; |
| 4926 | 19 | return false; | |
| 4927 | } | ||
| 4928 | |||
| 4929 |
4/8✓ Branch 1 taken 252 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 252 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 252 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 252 times.
✗ Branch 9 not taken.
|
252 | if(!M.vertices.single_precision() && M.vertices.nb() > 0) { |
| 4930 |
1/2✓ Branch 2 taken 252 times.
✗ Branch 3 not taken.
|
252 | index_t nb = M.vertices.nb() * M.vertices.dimension(); |
| 4931 |
1/2✓ Branch 1 taken 252 times.
✗ Branch 2 not taken.
|
252 | double* p = M.vertices.point_ptr(0); |
| 4932 | 252 | bool has_nan = false; | |
| 4933 |
2/2✓ Branch 0 taken 629211037 times.
✓ Branch 1 taken 252 times.
|
629211289 | for(index_t i = 0; i < nb; i++) { |
| 4934 |
2/4✓ Branch 1 taken 629211037 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 629211037 times.
|
629211037 | if(Numeric::is_nan(*p)) { |
| 4935 | ✗ | has_nan = true; | |
| 4936 | ✗ | *p = 0.0; | |
| 4937 | } | ||
| 4938 | 629211037 | p++; | |
| 4939 | } | ||
| 4940 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 252 times.
|
252 | if(has_nan) { |
| 4941 | ✗ | Logger::warn("I/O") << "Found NaNs in input file" << std::endl; | |
| 4942 | } | ||
| 4943 | } | ||
| 4944 | |||
| 4945 | 252 | if( | |
| 4946 |
6/10✓ Branch 1 taken 252 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 252 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 250 times.
✓ Branch 7 taken 2 times.
✓ Branch 9 taken 249 times.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
|
754 | FileSystem::extension(filename) != "geogram" && |
| 4947 |
7/12✓ Branch 1 taken 250 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 250 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 249 times.
✓ Branch 7 taken 1 times.
✓ Branch 8 taken 250 times.
✓ Branch 9 taken 2 times.
✓ Branch 11 taken 252 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
|
502 | FileSystem::extension(filename) != "geogram_ascii" |
| 4948 | ) { | ||
| 4949 |
1/2✓ Branch 1 taken 249 times.
✗ Branch 2 not taken.
|
249 | M.facets.connect(); |
| 4950 |
1/2✓ Branch 1 taken 249 times.
✗ Branch 2 not taken.
|
249 | M.cells.connect(); |
| 4951 |
6/6✓ Branch 1 taken 5 times.
✓ Branch 2 taken 244 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 4 times.
✓ Branch 7 taken 245 times.
|
249 | if(M.cells.nb() != 0 && M.facets.nb() == 0) { |
| 4952 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | M.cells.compute_borders(); |
| 4953 | } | ||
| 4954 | } | ||
| 4955 | |||
| 4956 |
1/2✓ Branch 1 taken 252 times.
✗ Branch 2 not taken.
|
252 | if(ioflags.verbose()) { |
| 4957 |
2/4✓ Branch 1 taken 252 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 252 times.
✗ Branch 5 not taken.
|
504 | M.show_stats("I/O"); |
| 4958 | } | ||
| 4959 | |||
| 4960 | 252 | return true; | |
| 4961 | 271 | } | |
| 4962 | |||
| 4963 | 151 | bool GEOGRAM_API mesh_save( | |
| 4964 | const Mesh& M, const std::string& filename, | ||
| 4965 | const MeshIOFlags& ioflags | ||
| 4966 | ) { | ||
| 4967 |
1/2✓ Branch 1 taken 151 times.
✗ Branch 2 not taken.
|
151 | if(ioflags.verbose()) { |
| 4968 |
2/4✓ Branch 1 taken 151 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 151 times.
✗ Branch 5 not taken.
|
453 | Logger::out("I/O") |
| 4969 |
3/6✓ Branch 1 taken 151 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 151 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 151 times.
✗ Branch 8 not taken.
|
151 | << "Saving file " << filename << "..." |
| 4970 |
1/2✓ Branch 1 taken 151 times.
✗ Branch 2 not taken.
|
151 | << std::endl; |
| 4971 | } | ||
| 4972 | |||
| 4973 |
1/2✓ Branch 1 taken 151 times.
✗ Branch 2 not taken.
|
151 | if( !FileSystem::can_write_directory( |
| 4974 |
3/6✓ Branch 1 taken 151 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 151 times.
✗ Branch 5 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 151 times.
|
302 | FileSystem::dir_name(FileSystem::absolute_path(filename)), true) |
| 4975 | ) { | ||
| 4976 | ✗ | Logger::err("I/O") << "Failed to open \"" | |
| 4977 | ✗ | << filename << "\" for writing" << std::endl; | |
| 4978 | ✗ | return false; | |
| 4979 | } | ||
| 4980 | |||
| 4981 |
1/2✓ Branch 1 taken 151 times.
✗ Branch 2 not taken.
|
151 | MeshIOHandler_var handler = MeshIOHandler::get_handler(filename); |
| 4982 |
5/10✓ Branch 1 taken 151 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 151 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 151 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 151 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 151 times.
✗ Branch 12 not taken.
|
151 | if(handler != nullptr && handler->save(M, filename, ioflags)) { |
| 4983 | 151 | return true; | |
| 4984 | } | ||
| 4985 | |||
| 4986 | ✗ | Logger::err("I/O") | |
| 4987 | ✗ | << "Could not save file: " << filename | |
| 4988 | ✗ | << std::endl; | |
| 4989 | ✗ | return false; | |
| 4990 | 151 | } | |
| 4991 | |||
| 4992 | /************************************************************************/ | ||
| 4993 | |||
| 4994 | |||
| 4995 | 422 | MeshIOHandler* MeshIOHandler::create(const std::string& format) { | |
| 4996 | 422 | MeshIOHandler* handler = MeshIOHandlerFactory::create_object( | |
| 4997 | format | ||
| 4998 | ); | ||
| 4999 |
2/2✓ Branch 0 taken 421 times.
✓ Branch 1 taken 1 times.
|
422 | if(handler != nullptr) { |
| 5000 | 421 | return handler; | |
| 5001 | } | ||
| 5002 | |||
| 5003 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
2 | Logger::err("I/O") |
| 5004 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | << "Unsupported file format: " << format |
| 5005 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | << std::endl; |
| 5006 | 1 | return nullptr; | |
| 5007 | } | ||
| 5008 | |||
| 5009 | 422 | MeshIOHandler* MeshIOHandler::get_handler( | |
| 5010 | const std::string& filename | ||
| 5011 | ) { | ||
| 5012 |
1/2✓ Branch 1 taken 422 times.
✗ Branch 2 not taken.
|
422 | std::string ext = FileSystem::extension(filename); |
| 5013 |
1/2✓ Branch 1 taken 422 times.
✗ Branch 2 not taken.
|
844 | return create(ext); |
| 5014 | 422 | } | |
| 5015 | |||
| 5016 | 842 | MeshIOHandler::~MeshIOHandler() { | |
| 5017 | 842 | } | |
| 5018 | |||
| 5019 | |||
| 5020 | 347 | void MeshIOHandler::bind_attributes( | |
| 5021 | const Mesh& M_in, const MeshIOFlags& flags, bool create | ||
| 5022 | ) { | ||
| 5023 | 347 | Mesh& M = const_cast<Mesh&>(M_in); // UGLY I know !! | |
| 5024 |
2/2✓ Branch 0 taken 233 times.
✓ Branch 1 taken 114 times.
|
347 | if(create) { |
| 5025 |
2/2✓ Branch 1 taken 13 times.
✓ Branch 2 taken 220 times.
|
233 | if(flags.has_attribute(MESH_VERTEX_REGION)) { |
| 5026 |
2/4✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 13 times.
✗ Branch 6 not taken.
|
39 | vertex_region_.bind(M.vertices.attributes(),"region"); |
| 5027 | } | ||
| 5028 |
2/2✓ Branch 1 taken 13 times.
✓ Branch 2 taken 220 times.
|
233 | if(flags.has_attribute(MESH_EDGE_REGION)) { |
| 5029 |
2/4✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 13 times.
✗ Branch 6 not taken.
|
39 | edge_region_.bind(M.edges.attributes(),"region"); |
| 5030 | } | ||
| 5031 |
2/2✓ Branch 1 taken 13 times.
✓ Branch 2 taken 220 times.
|
233 | if(flags.has_attribute(MESH_FACET_REGION)) { |
| 5032 |
2/4✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 13 times.
✗ Branch 6 not taken.
|
39 | facet_region_.bind(M.facets.attributes(),"region"); |
| 5033 | } | ||
| 5034 |
2/2✓ Branch 1 taken 13 times.
✓ Branch 2 taken 220 times.
|
233 | if(flags.has_attribute(MESH_CELL_REGION)) { |
| 5035 |
2/4✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 13 times.
✗ Branch 6 not taken.
|
39 | cell_region_.bind(M.cells.attributes(),"region"); |
| 5036 | } | ||
| 5037 | } else { | ||
| 5038 |
2/2✓ Branch 1 taken 17 times.
✓ Branch 2 taken 97 times.
|
114 | if(flags.has_attribute(MESH_VERTEX_REGION)) { |
| 5039 |
1/2✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
|
34 | vertex_region_.bind_if_is_defined( |
| 5040 |
1/2✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
|
51 | M.vertices.attributes(),"region" |
| 5041 | ); | ||
| 5042 | } | ||
| 5043 |
2/2✓ Branch 1 taken 17 times.
✓ Branch 2 taken 97 times.
|
114 | if(flags.has_attribute(MESH_EDGE_REGION)) { |
| 5044 |
1/2✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
|
34 | edge_region_.bind_if_is_defined( |
| 5045 |
1/2✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
|
51 | M.edges.attributes(),"region" |
| 5046 | ); | ||
| 5047 | } | ||
| 5048 |
2/2✓ Branch 1 taken 53 times.
✓ Branch 2 taken 61 times.
|
114 | if(flags.has_attribute(MESH_FACET_REGION)) { |
| 5049 |
1/2✓ Branch 2 taken 53 times.
✗ Branch 3 not taken.
|
106 | facet_region_.bind_if_is_defined( |
| 5050 |
1/2✓ Branch 1 taken 53 times.
✗ Branch 2 not taken.
|
159 | M.facets.attributes(),"region" |
| 5051 | ); | ||
| 5052 | } | ||
| 5053 |
2/2✓ Branch 1 taken 53 times.
✓ Branch 2 taken 61 times.
|
114 | if(flags.has_attribute(MESH_CELL_REGION)) { |
| 5054 |
1/2✓ Branch 2 taken 53 times.
✗ Branch 3 not taken.
|
106 | cell_region_.bind_if_is_defined( |
| 5055 |
1/2✓ Branch 1 taken 53 times.
✗ Branch 2 not taken.
|
159 | M.cells.attributes(),"region" |
| 5056 | ); | ||
| 5057 | } | ||
| 5058 | } | ||
| 5059 | 347 | } | |
| 5060 | |||
| 5061 | 345 | void MeshIOHandler::unbind_attributes() { | |
| 5062 |
2/2✓ Branch 1 taken 26 times.
✓ Branch 2 taken 319 times.
|
345 | if(vertex_region_.is_bound()) { |
| 5063 | 26 | vertex_region_.unbind(); | |
| 5064 | } | ||
| 5065 |
2/2✓ Branch 1 taken 26 times.
✓ Branch 2 taken 319 times.
|
345 | if(edge_region_.is_bound()) { |
| 5066 | 26 | edge_region_.unbind(); | |
| 5067 | } | ||
| 5068 |
2/2✓ Branch 1 taken 62 times.
✓ Branch 2 taken 283 times.
|
345 | if(facet_region_.is_bound()) { |
| 5069 | 62 | facet_region_.unbind(); | |
| 5070 | } | ||
| 5071 |
2/2✓ Branch 1 taken 26 times.
✓ Branch 2 taken 319 times.
|
345 | if(cell_region_.is_bound()) { |
| 5072 | 26 | cell_region_.unbind(); | |
| 5073 | } | ||
| 5074 | 345 | } | |
| 5075 | |||
| 5076 | |||
| 5077 | 251 | void mesh_io_initialize() { | |
| 5078 |
4/10✓ Branch 0 taken 251 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 251 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 251 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 251 times.
✗ Branch 10 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
|
753 | geo_register_MeshIOHandler_creator(LMIOHandler, "mesh"); |
| 5079 |
4/10✓ Branch 0 taken 251 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 251 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 251 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 251 times.
✗ Branch 10 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
|
753 | geo_register_MeshIOHandler_creator(LMIOHandler, "meshb"); |
| 5080 |
4/10✓ Branch 0 taken 251 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 251 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 251 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 251 times.
✗ Branch 10 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
|
753 | geo_register_MeshIOHandler_creator(OBJIOHandler, "obj"); |
| 5081 |
4/10✓ Branch 0 taken 251 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 251 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 251 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 251 times.
✗ Branch 10 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
|
753 | geo_register_MeshIOHandler_creator(OBJIOHandler, "eobj"); |
| 5082 |
4/10✓ Branch 0 taken 251 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 251 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 251 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 251 times.
✗ Branch 10 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
|
753 | geo_register_MeshIOHandler_creator(OBJ6IOHandler, "obj6"); |
| 5083 |
4/10✓ Branch 0 taken 251 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 251 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 251 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 251 times.
✗ Branch 10 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
|
753 | geo_register_MeshIOHandler_creator(PLYIOHandler, "ply"); |
| 5084 |
4/10✓ Branch 0 taken 251 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 251 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 251 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 251 times.
✗ Branch 10 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
|
753 | geo_register_MeshIOHandler_creator(OFFIOHandler, "off"); |
| 5085 |
4/10✓ Branch 0 taken 251 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 251 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 251 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 251 times.
✗ Branch 10 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
|
753 | geo_register_MeshIOHandler_creator(STLIOHandler, "stl"); |
| 5086 |
4/10✓ Branch 0 taken 251 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 251 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 251 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 251 times.
✗ Branch 10 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
|
753 | geo_register_MeshIOHandler_creator(XYZIOHandler, "xyz"); |
| 5087 |
4/10✓ Branch 0 taken 251 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 251 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 251 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 251 times.
✗ Branch 10 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
|
753 | geo_register_MeshIOHandler_creator(PTSIOHandler, "pts"); |
| 5088 |
4/10✓ Branch 0 taken 251 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 251 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 251 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 251 times.
✗ Branch 10 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
|
753 | geo_register_MeshIOHandler_creator(TETIOHandler, "tet"); |
| 5089 |
4/10✓ Branch 0 taken 251 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 251 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 251 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 251 times.
✗ Branch 10 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
|
753 | geo_register_MeshIOHandler_creator(TET6IOHandler, "tet6"); |
| 5090 |
4/10✓ Branch 0 taken 251 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 251 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 251 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 251 times.
✗ Branch 10 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
|
753 | geo_register_MeshIOHandler_creator(TET8IOHandler, "tet8"); |
| 5091 |
4/10✓ Branch 0 taken 251 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 251 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 251 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 251 times.
✗ Branch 10 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
|
753 | geo_register_MeshIOHandler_creator(GeogramIOHandler, "geogram"); |
| 5092 |
4/10✓ Branch 0 taken 251 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 251 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 251 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 251 times.
✗ Branch 10 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
|
753 | geo_register_MeshIOHandler_creator(GeogramIOHandler, "geogram_ascii"); |
| 5093 |
4/10✓ Branch 0 taken 251 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 251 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 251 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 251 times.
✗ Branch 10 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
|
753 | geo_register_MeshIOHandler_creator(GraphiteIOHandler, "graphite"); |
| 5094 |
4/10✓ Branch 0 taken 251 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 251 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 251 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 251 times.
✗ Branch 10 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
|
753 | geo_register_MeshIOHandler_creator(PDBIOHandler, "pdb"); |
| 5095 |
4/10✓ Branch 0 taken 251 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 251 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 251 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 251 times.
✗ Branch 10 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
|
753 | geo_register_MeshIOHandler_creator(PDBIOHandler, "pdb1"); |
| 5096 |
4/10✓ Branch 0 taken 251 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 251 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 251 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 251 times.
✗ Branch 10 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
|
753 | geo_register_MeshIOHandler_creator(OVMIOHandler, "ovm"); |
| 5097 |
4/10✓ Branch 0 taken 251 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 251 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 251 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 251 times.
✗ Branch 10 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
|
753 | geo_register_MeshIOHandler_creator(MSHIOHandler, "msh"); |
| 5098 | 251 | } | |
| 5099 | |||
| 5100 | |||
| 5101 | ✗ | bool GEOGRAM_API mesh_load( | |
| 5102 | InputGeoFile& geofile, Mesh& M, | ||
| 5103 | const MeshIOFlags& ioflags | ||
| 5104 | ) { | ||
| 5105 | ✗ | GeogramIOHandler geogram; | |
| 5106 | ✗ | return geogram.load(geofile, M, ioflags); | |
| 5107 | ✗ | } | |
| 5108 | |||
| 5109 | ✗ | bool GEOGRAM_API mesh_save( | |
| 5110 | const Mesh& M, OutputGeoFile& geofile, | ||
| 5111 | const MeshIOFlags& ioflags | ||
| 5112 | ) { | ||
| 5113 | ✗ | GeogramIOHandler geogram; | |
| 5114 | ✗ | return geogram.save(M, geofile, ioflags); | |
| 5115 | ✗ | } | |
| 5116 | |||
| 5117 | ✗ | bool Mesh::load(const std::string& filename) { | |
| 5118 | ✗ | return mesh_load(filename, *this); | |
| 5119 | } | ||
| 5120 | |||
| 5121 | ✗ | bool Mesh::save(const std::string& filename) const { | |
| 5122 | ✗ | return mesh_save(*this, filename); | |
| 5123 | } | ||
| 5124 | |||
| 5125 | } | ||
| 5126 |