1 /*
2 MDAL - Mesh Data Abstraction Library (MIT License)
3 Copyright (C) 2020 Lutra Consulting Ltd.
4 */
5
6 #include <stddef.h>
7 #include <iosfwd>
8 #include <iostream>
9 #include <fstream>
10 #include <sstream>
11 #include <string>
12 #include <vector>
13 #include <map>
14 #include <cassert>
15 #include <limits>
16 #include <algorithm>
17
18 #include "mdal_xms_tin.hpp"
19 #include "mdal.h"
20 #include "mdal_utils.hpp"
21 #include "mdal_logger.hpp"
22
23 #define DRIVER_NAME "XMS_TIN"
24
DriverXmsTin()25 MDAL::DriverXmsTin::DriverXmsTin():
26 Driver( DRIVER_NAME,
27 "XMS Tin Mesh File",
28 "*.tin",
29 Capability::ReadMesh
30 )
31 {
32 }
33
create()34 MDAL::DriverXmsTin *MDAL::DriverXmsTin::create()
35 {
36 return new DriverXmsTin();
37 }
38
faceVerticesMaximumCount() const39 int MDAL::DriverXmsTin::faceVerticesMaximumCount() const
40 {
41 return MAX_VERTICES_PER_FACE_TIN;
42 }
43
44 MDAL::DriverXmsTin::~DriverXmsTin() = default;
45
canReadMesh(const std::string & uri)46 bool MDAL::DriverXmsTin::canReadMesh( const std::string &uri )
47 {
48 std::ifstream in = MDAL::openInputFile( uri, std::ifstream::in );
49 std::string line;
50 if ( !MDAL::getHeaderLine( in, line ) || !startsWith( line, "TIN" ) )
51 {
52 return false;
53 }
54 return true;
55 }
56
load(const std::string & meshFile,const std::string &)57 std::unique_ptr<MDAL::Mesh> MDAL::DriverXmsTin::load( const std::string &meshFile, const std::string & )
58 {
59 MDAL::Log::resetLastStatus();
60
61 std::ifstream in = MDAL::openInputFile( meshFile, std::ifstream::in );
62 std::string line;
63 // skip first line with "TIN" already checked in the canReadMesh
64 std::getline( in, line );
65
66 // Read vertices
67 if ( !std::getline( in, line ) || !startsWith( line, "BEGT" ) )
68 {
69 MDAL::Log::error( MDAL_Status::Err_UnknownFormat, name(), meshFile + " second line does not start with BEGT keyword" );
70 return nullptr;
71 }
72 if ( !std::getline( in, line ) )
73 {
74 MDAL::Log::error( MDAL_Status::Err_IncompatibleMesh, name(), meshFile + " does not contain 3rd line" );
75 return nullptr;
76 }
77 std::vector<std::string> chunks = split( line, ' ' );
78 if ( ( chunks.size() != 2 ) || ( chunks[0] != "VERT" ) )
79 {
80 MDAL::Log::error( MDAL_Status::Err_IncompatibleMesh, name(), meshFile + " 4th line does not contain VERT keyword with number of vertices" );
81 return nullptr;
82 }
83 size_t vertexCount = MDAL::toSizeT( chunks[1] );
84 Vertices vertices( vertexCount );
85 for ( size_t i = 0; i < vertexCount; ++i )
86 {
87 if ( !std::getline( in, line ) )
88 {
89 MDAL::Log::error( MDAL_Status::Err_IncompatibleMesh, name(), meshFile + " does not contain enough vertex definitions" );
90 return nullptr;
91 }
92 chunks = split( line, ' ' );
93 if ( chunks.size() != 4 )
94 {
95 MDAL::Log::error( MDAL_Status::Err_IncompatibleMesh, name(), meshFile + " does not contain valid vertex definition" );
96 return nullptr;
97 }
98
99 Vertex &vertex = vertices[i];
100 vertex.x = MDAL::toDouble( chunks[0] );
101 vertex.y = MDAL::toDouble( chunks[1] );
102 vertex.z = MDAL::toDouble( chunks[2] );
103 }
104
105 // Read triangles
106 if ( !std::getline( in, line ) )
107 {
108 MDAL::Log::error( MDAL_Status::Err_IncompatibleMesh, name(), meshFile + " does not contain valid triangle definition" );
109 return nullptr;
110 }
111 chunks = split( line, ' ' );
112 if ( ( chunks.size() != 2 ) || ( chunks[0] != "TRI" ) )
113 {
114 MDAL::Log::error( MDAL_Status::Err_IncompatibleMesh, name(), meshFile + " does not contain TRI keyword" );
115 return nullptr;
116 }
117 size_t faceCount = MDAL::toSizeT( chunks[1] );
118 Faces faces( faceCount );
119 for ( size_t i = 0; i < faceCount; ++i )
120 {
121 if ( !std::getline( in, line ) )
122 {
123 MDAL::Log::error( MDAL_Status::Err_IncompatibleMesh, name(), meshFile + " does not contain enough triangle definitions" );
124 return nullptr;
125 }
126 chunks = split( line, ' ' );
127 if ( chunks.size() != 3 )
128 {
129 // should have 3 indexes
130 MDAL::Log::error( MDAL_Status::Err_IncompatibleMesh, name(), meshFile + " does not contain valid triangle definition" );
131 return nullptr;
132 }
133
134 Face &face = faces[i];
135 face.resize( MAX_VERTICES_PER_FACE_TIN );
136 face[0] = MDAL::toSizeT( chunks[0] ) - 1;
137 face[1] = MDAL::toSizeT( chunks[1] ) - 1;
138 face[2] = MDAL::toSizeT( chunks[2] ) - 1;
139 }
140
141 // Final keyword
142 if ( !std::getline( in, line ) || !startsWith( line, "ENDT" ) )
143 {
144 MDAL::Log::error( MDAL_Status::Err_IncompatibleMesh, name(), meshFile + " does not end with ENDT keyword" );
145 return nullptr;
146 }
147
148 std::unique_ptr< MemoryMesh > mesh(
149 new MemoryMesh(
150 DRIVER_NAME,
151 MAX_VERTICES_PER_FACE_TIN,
152 meshFile
153 )
154 );
155 mesh->setFaces( std::move( faces ) );
156 mesh->setVertices( std::move( vertices ) );
157
158 // Add Bed Elevation
159 MDAL::addBedElevationDatasetGroup( mesh.get(), mesh->vertices() );
160
161 return std::unique_ptr<Mesh>( mesh.release() );
162 }
163