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