• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

lutraconsulting / MDAL / 4292411804

pending completion
4292411804

Pull #446

github

GitHub
Merge 2934e06c8 into 06c59ac6b
Pull Request #446: Some backports

100 of 100 new or added lines in 3 files covered. (100.0%)

8925 of 9966 relevant lines covered (89.55%)

75594.54 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.48
/mdal/mdal_utils.cpp
1
/*
2
 MDAL - Mesh Data Abstraction Library (MIT License)
3
 Copyright (C) 2018 Peter Petrik (zilolv at gmail dot com)
4
*/
5

6
#include "mdal_utils.hpp"
7
#include <string>
8
#include <fstream>
9
#include <iostream>
10
#include <algorithm>
11
#include <sstream>
12
#include <math.h>
13
#include <assert.h>
14
#include <string.h>
15
#include <stdio.h>
16
#include <ctime>
17
#include <stdlib.h>
18

19
#ifdef _MSC_VER
20
#define UNICODE
21
#include <locale>
22
#include <codecvt>
23
#include <stringapiset.h>
24
#endif
25

26
std::string MDAL::getEnvVar( const std::string &varname, const std::string &defaultVal )
27✔
27
{
28
  if ( varname.empty() )
27✔
29
    return std::string();
×
30

31
  char *envVarC = getenv( varname.c_str() );
27✔
32

33
  if ( !envVarC )
27✔
34
    return defaultVal;
26✔
35
  else
36
    return std::string( envVarC );
1✔
37
}
38

39
bool MDAL::openInputFile( std::ifstream &inputFileStream, const std::string &fileName, std::ios_base::openmode mode )
1,296✔
40
{
41
#ifdef _MSC_VER
42
  std::wstring_convert< std::codecvt_utf8_utf16< wchar_t > > converter;
43
  std::wstring wStr = converter.from_bytes( fileName );
44
  inputFileStream.open( wStr, std::ifstream::in | mode );
45
#else
46
  inputFileStream.open( fileName, std::ifstream::in | mode );
1,296✔
47
#endif
48

49
  return inputFileStream.is_open();
1,296✔
50
}
51

52
std::ifstream MDAL::openInputFile( const std::string &fileName, std::ios_base::openmode mode )
1,287✔
53
{
54
  std::ifstream ret;
1,287✔
55

56
#ifdef _MSC_VER
57
  std::wstring_convert< std::codecvt_utf8_utf16< wchar_t > > converter;
58
  std::wstring wStr = converter.from_bytes( fileName );
59
  ret.open( wStr, mode );
60
#else
61
  ret.open( fileName, mode );
1,287✔
62
#endif
63

64
  return ret;
1,287✔
65
}
×
66

67
std::ofstream MDAL::openOutputFile( const std::string &fileName, std::ios_base::openmode mode )
20✔
68
{
69
  std::ofstream ret;
20✔
70

71
#ifdef _MSC_VER
72
  std::wstring_convert< std::codecvt_utf8_utf16< wchar_t > > converter;
73
  std::wstring wStr = converter.from_bytes( fileName );
74
  ret.open( wStr, mode );
75
#else
76
  ret.open( fileName, mode );
20✔
77
#endif
78

79
  return ret;
20✔
80
}
×
81

82
bool MDAL::fileExists( const std::string &filename )
1,296✔
83
{
84
  std::ifstream in;
1,296✔
85

86
  if ( !openInputFile( in, filename ) )
1,296✔
87
    return false;
157✔
88

89
  return in.good();
1,139✔
90
}
1,296✔
91

92
std::string MDAL::readFileToString( const std::string &filename )
6✔
93
{
94
  if ( MDAL::fileExists( filename ) )
6✔
95
  {
96
    std::ifstream t = openInputFile( filename );
1✔
97

98
    std::stringstream buffer;
1✔
99
    buffer << t.rdbuf();
1✔
100
    return buffer.str();
1✔
101
  }
1✔
102
  return "";
5✔
103
}
104

105
bool MDAL::startsWith( const std::string &str, const std::string &substr, ContainsBehaviour behaviour )
1,093,283✔
106
{
107
  if ( ( str.size() < substr.size() ) || substr.empty() )
1,093,283✔
108
    return false;
511✔
109

110
  if ( behaviour == ContainsBehaviour::CaseSensitive )
1,092,772✔
111
    return str.rfind( substr, 0 ) == 0;
1,091,636✔
112
  else
113
    return startsWith( toLower( str ), toLower( substr ), ContainsBehaviour::CaseSensitive );
1,136✔
114
}
115

116
bool MDAL::endsWith( const std::string &str, const std::string &substr, ContainsBehaviour behaviour )
133✔
117
{
118
  if ( ( str.size() < substr.size() ) || substr.empty() )
133✔
119
    return false;
23✔
120

121
  if ( behaviour == ContainsBehaviour::CaseSensitive )
110✔
122
    return str.rfind( substr ) == ( str.size() - substr.size() );
103✔
123
  else
124
    return endsWith( toLower( str ), toLower( substr ), ContainsBehaviour::CaseSensitive );
7✔
125
}
126

127
std::vector<std::string> MDAL::split( const std::string &str,
272,769✔
128
                                      const char delimiter
129
                                    )
130
{
131
  std::vector<std::string> list;
272,769✔
132
  std::string::const_iterator start = str.begin();
272,769✔
133
  std::string::const_iterator end = str.end();
272,769✔
134
  std::string::const_iterator next;
272,769✔
135
  std::string token;
272,769✔
136
  do
137
  {
138
    next = std::find( start, end, delimiter );
6,906,002✔
139
    token = std::string( start, next );
6,906,002✔
140
    if ( !token.empty() )
6,906,002✔
141
      list.push_back( token );
1,822,129✔
142

143
    if ( next == end )
6,906,002✔
144
      break;
272,769✔
145
    else
146
      start = next + 1;
6,633,233✔
147
  }
148
  while ( true );
149
  return list;
545,538✔
150
}
272,769✔
151

152

153
std::vector<std::string> MDAL::split( const std::string &str,
546✔
154
                                      const std::string &delimiter )
155
{
156
  std::vector<std::string> list;
546✔
157
  std::string::size_type start = 0;
546✔
158
  std::string::size_type next;
159
  std::string token;
546✔
160
  do
161
  {
162
    next = str.find( delimiter, start );
1,308✔
163
    if ( next == std::string::npos )
1,308✔
164
      token = str.substr( start ); // rest of the string
546✔
165
    else
166
      token = str.substr( start, next - start ); // part of the string
762✔
167
    if ( !token.empty() )
1,308✔
168
      list.push_back( token );
1,064✔
169
    start = next + delimiter.size();
1,308✔
170
  }
171
  while ( next != std::string::npos );
1,308✔
172
  return list;
1,092✔
173
}
546✔
174

175
size_t MDAL::toSizeT( const std::string &str )
588,672✔
176
{
177
  int i = atoi( str.c_str() );
588,672✔
178
  if ( i < 0 ) // consistent with atoi return
588,672✔
179
    i = 0;
×
180
  return static_cast< size_t >( i );
588,672✔
181
}
182

183
size_t MDAL::toSizeT( const char &str )
111,709✔
184
{
185
  int i = atoi( &str );
111,709✔
186
  if ( i < 0 ) // consistent with atoi return
111,709✔
187
    i = 0;
×
188
  return static_cast< size_t >( i );
111,709✔
189
}
190

191
size_t MDAL::toSizeT( const double value )
16,528✔
192
{
193
  return static_cast<size_t>( value );
16,528✔
194
}
195

196
size_t MDAL::toSizeT( const int value )
×
197
{
198
  return static_cast<size_t>( value );
×
199
}
200

201
int MDAL::toInt( const size_t value )
220,788✔
202
{
203
  if ( value > std::numeric_limits<int>::max() )
220,788✔
204
    throw std::runtime_error( "Invalid cast" );
×
205
  return static_cast< int >( value );
220,788✔
206
}
207

208
double MDAL::toDouble( const size_t value )
×
209
{
210
  return static_cast< double >( value );
×
211
}
212

213
double MDAL::toDouble( const std::string &str )
455,458✔
214
{
215
  return atof( str.c_str() );
455,458✔
216
}
217

218
int MDAL::toInt( const std::string &str )
431✔
219
{
220
  return atoi( str.c_str() );
431✔
221
}
222

223
std::string MDAL::baseName( const std::string &filename, bool keepExtension )
61✔
224
{
225
  // https://stackoverflow.com/a/8520815/2838364
226
  std::string fname( filename );
61✔
227

228
  // Remove directory if present.
229
  // Do this before extension removal incase directory has a period character.
230
  const size_t last_slash_idx = fname.find_last_of( "\\/" );
61✔
231
  if ( std::string::npos != last_slash_idx )
61✔
232
  {
233
    fname.erase( 0, last_slash_idx + 1 );
54✔
234
  }
235

236
  if ( !keepExtension )
61✔
237
  {
238
    // Remove extension if present.
239
    const size_t period_idx = fname.rfind( '.' );
26✔
240
    if ( std::string::npos != period_idx )
26✔
241
    {
242
      fname.erase( period_idx );
26✔
243
    }
244
  }
245
  return fname;
61✔
246
}
×
247

248
std::string MDAL::fileExtension( const std::string &path )
35✔
249
{
250
  std::string filename = MDAL::baseName( path, true );
35✔
251

252
  const size_t lastDotIx = filename.find_last_of( "." );
35✔
253
  if ( std::string::npos == lastDotIx )
35✔
254
  {
255
    return std::string();
3✔
256
  }
257

258
  std::string extension = filename.substr( lastDotIx );
32✔
259

260
  return extension;
32✔
261
}
35✔
262

263
std::string MDAL::pathJoin( const std::string &path1, const std::string &path2 )
859✔
264
{
265
//https://stackoverflow.com/questions/6297738/how-to-build-a-full-path-string-safely-from-separate-strings#6297807
266
#ifdef _MSC_VER
267
  return path1 + "\\" + path2;
268
#else
269
  return path1 + "/" + path2;
1,718✔
270
#endif
271
}
272

273
std::string MDAL::dirName( const std::string &filename )
1,066✔
274
{
275
  std::string dname( filename );
1,066✔
276
  const size_t last_slash_idx = dname.find_last_of( "\\/" );
1,066✔
277
  if ( std::string::npos != last_slash_idx )
1,066✔
278
  {
279
    dname.erase( last_slash_idx, dname.size() - last_slash_idx );
1,066✔
280
  }
281
  return dname;
1,066✔
282
}
×
283

284
bool MDAL::contains( const std::string &str, const std::string &substr, ContainsBehaviour behaviour )
9,633✔
285
{
286
  if ( behaviour == ContainsBehaviour::CaseSensitive )
9,633✔
287
    return str.find( substr ) != std::string::npos;
5,550✔
288
  else
289
  {
290
    auto it = std::search(
4,083✔
291
                str.begin(), str.end(),
292
                substr.begin(),   substr.end(),
293
                []( char ch1, char ch2 )
88,637✔
294
    {
295
#ifdef _MSC_VER
296
      return toupper( ch1 ) == toupper( ch2 );
297
#else
298
      return std::toupper( ch1 ) == std::toupper( ch2 );
88,637✔
299
#endif
300
    }
301
              );
302
    return ( it != str.end() );
4,083✔
303
  }
304
}
305

306
bool MDAL::toBool( const std::string &str )
22✔
307
{
308
  int i = atoi( str.c_str() );
22✔
309
  return i != 0;
22✔
310
}
311

312
bool MDAL::contains( const std::vector<std::string> &list, const std::string &str )
275✔
313
{
314
  return std::find( list.begin(), list.end(), str ) != list.end();
275✔
315
}
316

317
std::string MDAL::join( const std::vector<std::string> parts, const std::string &delimiter )
8,285✔
318
{
319
  std::stringstream res;
8,285✔
320
  for ( auto iter = parts.begin(); iter != parts.end(); iter++ )
16,582✔
321
  {
322
    if ( iter != parts.begin() ) res << delimiter;
8,297✔
323
    res << *iter;
8,297✔
324
  }
325
  return res.str();
16,570✔
326
}
8,285✔
327

328
std::string MDAL::leftJustified( const std::string &str, size_t width, char fill )
2✔
329
{
330
  std::string ret( str );
2✔
331
  if ( ret.size() > width )
2✔
332
  {
333
    ret = ret.substr( 0, width );
×
334
  }
335
  else
336
  {
337
    ret = ret + std::string( width - ret.size(), fill );
2✔
338
  }
339
  assert( ret.size() == width );
2✔
340
  return ret;
2✔
341
}
×
342

343
std::string MDAL::toLower( const std::string &std )
15,022✔
344
{
345
  std::string res( std );
15,022✔
346
#ifdef _MSC_VER
347
  //silence algorithm(1443): warning C4244: '=': conversion from 'int' to 'char'
348
  std::transform( res.begin(), res.end(), res.begin(),
349
  []( char c ) {return static_cast<char>( ::tolower( c ) );} );
350
#else
351
  std::transform( res.begin(), res.end(), res.begin(), ::tolower );
15,022✔
352
#endif
353
  return res;
15,022✔
354
}
355

356
std::string MDAL::replace( const std::string &str, const std::string &substr, const std::string &replacestr, MDAL::ContainsBehaviour behaviour )
3,429✔
357
{
358
  std::string res( str );
3,429✔
359
  if ( behaviour == ContainsBehaviour::CaseSensitive )
3,429✔
360
  {
361
    while ( res.find( substr ) != std::string::npos )
1,745✔
362
    {
363
      res.replace( res.find( substr ), substr.size(), replacestr );
514✔
364
    }
365
  }
366
  else
367
  {
368
    // https://stackoverflow.com/a/40577390/2838364
369
    std::string lower_s = toLower( str );
2,198✔
370
    std::string lower_substring = toLower( substr );
2,198✔
371

372
    auto position = lower_s.find( lower_substring );
2,198✔
373
    while ( position != std::string::npos )
2,274✔
374
    {
375
      res.replace( position, lower_substring.size(), replacestr );
76✔
376
      lower_s.replace( position, lower_substring.size(), replacestr );
76✔
377
      position = lower_s.find( lower_substring );
76✔
378
    }
379
  }
2,198✔
380
  return res;
3,429✔
381
}
×
382

383
std::string MDAL::removeFrom( const std::string &str, const std::string &substr )
15✔
384
{
385
  std::string res( str );
15✔
386
  size_t pos = res.rfind( substr );
15✔
387
  if ( pos != std::string::npos )
15✔
388
  {
389
    res = res.substr( 0, pos );
9✔
390
  }
391
  return res;
15✔
392

393
}
×
394

395
// http://www.cplusplus.com/faq/sequences/strings/trim/
396
std::string MDAL::trim( const std::string &s, const std::string &delimiters )
3,064✔
397
{
398
  if ( s.empty() )
3,064✔
399
    return s;
28✔
400

401
  return ltrim( rtrim( s, delimiters ), delimiters );
6,072✔
402
}
403

404
#ifdef _MSC_VER
405
static std::string utf8ToWin32Recode( const std::string &utf8String )
406
{
407
  //from GDAL: ./port/cpl_recode_stub.cpp, CPLWin32Recode()
408

409
  // Compute length in wide characters
410
  int wlen = MultiByteToWideChar( CP_UTF8, 0, utf8String.c_str(), -1, nullptr, 0 );
411

412
  // do the conversion to wide char
413
  std::wstring wstr;
414
  wstr.resize( MDAL::toSizeT( wlen ) + 1 );
415
  wstr.data()[wlen] = 0;
416
  MultiByteToWideChar( CP_UTF8, 0, utf8String.c_str(), -1, wstr.data(), wstr.size() );
417

418
  int len = WideCharToMultiByte( CP_ACP, 0, wstr.c_str(), -1, nullptr, 0, nullptr, nullptr );
419

420
  std::string ret;
421
  ret.resize( MDAL::toSizeT( len ) + 1 );
422

423
  WideCharToMultiByte( CP_ACP, 0, wstr.c_str(), -1, ret.data(), ret.size(), nullptr, nullptr );
424

425
  return ret;
426
}
427
#endif
428

429
std::string MDAL::systemFileName( const std::string &utf8FileName )
366✔
430
{
431
  std::string ret;
366✔
432
#ifdef _MSC_VER
433
  ret = utf8ToWin32Recode( utf8FileName );
434
#else
435
  ret = utf8FileName;
366✔
436
#endif
437
  return ret;
366✔
438
}
×
439

440
// http://www.cplusplus.com/faq/sequences/strings/trim/
441
std::string MDAL::ltrim( const std::string &s, const std::string &delimiters )
3,043✔
442
{
443
  if ( s.empty() )
3,043✔
444
    return s;
74✔
445

446
  size_t found = s.find_first_not_of( delimiters );
2,969✔
447

448
  if ( found == std::string::npos )
2,969✔
449
  {
450
    return "";
1✔
451
  }
452
  else
453
  {
454
    return s.substr( found );
2,968✔
455
  }
456
}
457

458
// http://www.cplusplus.com/faq/sequences/strings/trim/
459
std::string MDAL::rtrim( const std::string &s, const std::string &delimiters )
66,324✔
460
{
461
  if ( s.empty() )
66,324✔
462
    return s;
1✔
463

464
  size_t found = s.find_last_not_of( delimiters );
66,323✔
465
  if ( found == std::string::npos )
66,323✔
466
  {
467
    return "";
80✔
468
  }
469
  else
470
  {
471
    return s.substr( 0, found + 1 );
66,243✔
472
  }
473
}
474

475
MDAL::BBox MDAL::computeExtent( const MDAL::Vertices &vertices )
178✔
476
{
477
  BBox b;
178✔
478

479
  if ( vertices.empty() )
178✔
480
    return b;
1✔
481

482
  b.minX = vertices[0].x;
177✔
483
  b.maxX = vertices[0].x;
177✔
484
  b.minY = vertices[0].y;
177✔
485
  b.maxY = vertices[0].y;
177✔
486

487
  for ( Vertices::size_type i = 0; i < vertices.size(); i++ )
1,026,055✔
488
  {
489
    const Vertex &n = vertices[i];
1,025,878✔
490
    if ( n.x > b.maxX ) b.maxX = n.x;
1,025,878✔
491
    if ( n.x < b.minX ) b.minX = n.x;
1,025,878✔
492
    if ( n.y > b.maxY ) b.maxY = n.y;
1,025,878✔
493
    if ( n.y < b.minY ) b.minY = n.y;
1,025,878✔
494
  }
495
  return b;
177✔
496
}
497

498
double MDAL::safeValue( double val, double nodata, double eps )
4,997,086✔
499
{
500
  if ( std::isnan( val ) )
4,997,086✔
501
    return val;
182,773✔
502

503
  if ( std::isnan( nodata ) )
4,814,313✔
504
    return val;
1,727,534✔
505

506
  if ( equals( val, nodata, eps ) )
3,086,779✔
507
    return std::numeric_limits<double>::quiet_NaN();
54,869✔
508

509
  return val;
3,031,910✔
510
}
511

512
double MDAL::parseTimeUnits( const std::string &units )
6✔
513
{
514
  double divBy = 1;
6✔
515
  // We are trying to parse strings like
516
  //
517
  // "seconds since 2001-05-05 00:00:00"
518
  // "hours since 1900-01-01 00:00:0.0"
519
  // "days since 1961-01-01 00:00:00"
520
  //
521
  // or simply
522
  // hours, days, seconds, ...
523

524
  const std::vector<std::string> units_list = MDAL::split( units, " since " );
12✔
525
  std::string unit_definition = units;
6✔
526
  if ( !units_list.empty() )
6✔
527
  {
528
    unit_definition = units_list[0];
6✔
529
  }
530

531
  // Give me hours
532
  if ( units_list[0] == "seconds" )
6✔
533
  {
534
    divBy = 3600.0;
1✔
535
  }
536
  else if ( units_list[0] == "minutes" )
5✔
537
  {
538
    divBy = 60.0;
1✔
539
  }
540
  else if ( units_list[0] == "days" )
4✔
541
  {
542
    divBy = 1.0 / 24.0;
1✔
543
  }
544

545
  return divBy;
6✔
546
}
6✔
547

548
std::string MDAL::getCurrentTimeStamp()
10✔
549
{
550
  time_t t ;
551
  struct tm *tmp ;
552
  char MY_TIME[50];
553
  time( &t );
10✔
554
  tmp = localtime( &t );
10✔
555
  strftime( MY_TIME, sizeof( MY_TIME ), "%Y-%m-%dT%H:%M:%S%z", tmp );
10✔
556
  std::string s = MDAL::trim( MY_TIME );
20✔
557
  return s;
20✔
558
}
559

560
MDAL::Statistics _calculateStatistics( const std::vector<double> &values, size_t count, bool isVector, const std::vector<int> &active )
14,115✔
561
{
562
  MDAL::Statistics ret;
14,115✔
563

564
  double min = std::numeric_limits<double>::quiet_NaN();
14,115✔
565
  double max = std::numeric_limits<double>::quiet_NaN();
14,115✔
566
  bool firstIteration = true;
14,115✔
567

568
  for ( size_t i = 0; i < count; ++i )
18,184,097✔
569
  {
570
    if ( !active.empty() && active.at( i ) == 0 )
18,169,982✔
571
      continue;
67,865✔
572

573
    double magnitude;
574
    if ( isVector )
18,102,117✔
575
    {
576
      double x = values[2 * i];
5,083,858✔
577
      double y = values[2 * i + 1];
5,083,858✔
578
      if ( std::isnan( x ) || std::isnan( y ) )
5,083,858✔
579
        continue;
289,308✔
580
      magnitude = sqrt( x * x + y * y );
4,794,550✔
581
    }
582
    else
583
    {
584
      double x = values[i];
13,018,259✔
585
      if ( std::isnan( x ) )
13,018,259✔
586
        continue;
1,786,482✔
587
      magnitude = x;
11,231,777✔
588
    }
589

590
    if ( firstIteration )
16,026,327✔
591
    {
592
      firstIteration = false;
13,741✔
593
      min = magnitude;
13,741✔
594
      max = magnitude;
13,741✔
595
    }
596
    else
597
    {
598
      if ( magnitude < min )
16,012,586✔
599
      {
600
        min = magnitude;
109,533✔
601
      }
602
      if ( magnitude > max )
16,012,586✔
603
      {
604
        max = magnitude;
511,669✔
605
      }
606
    }
607
  }
608

609
  ret.minimum = min;
14,115✔
610
  ret.maximum = max;
14,115✔
611
  return ret;
14,115✔
612
}
613

614
MDAL::Statistics MDAL::calculateStatistics( std::shared_ptr<MDAL::DatasetGroup> grp )
764✔
615
{
616
  return calculateStatistics( grp.get() );
764✔
617
}
618

619
MDAL::Statistics MDAL::calculateStatistics( DatasetGroup *grp )
873✔
620
{
621
  Statistics ret;
873✔
622
  if ( !grp )
873✔
623
    return ret;
×
624

625
  for ( std::shared_ptr<Dataset> &ds : grp->datasets )
8,839✔
626
  {
627
    MDAL::Statistics dsStats = ds->statistics();
7,966✔
628
    combineStatistics( ret, dsStats );
7,966✔
629
  }
630
  return ret;
873✔
631
}
632

633
MDAL::Statistics MDAL::calculateStatistics( std::shared_ptr<Dataset> dataset )
7,966✔
634
{
635
  Statistics ret;
7,966✔
636
  if ( !dataset )
7,966✔
637
    return ret;
×
638

639
  bool isVector = !dataset->group()->isScalar();
7,966✔
640
  bool is3D = dataset->group()->dataLocation() == MDAL_DataLocation::DataOnVolumes;
7,966✔
641
  size_t bufLen = 2000;
7,966✔
642
  std::vector<double> buffer( isVector ? bufLen * 2 : bufLen );
7,966✔
643
  std::vector<int> activeBuffer;
7,966✔
644
  bool activeFaceFlag = dataset->group()->dataLocation() == MDAL_DataLocation::DataOnFaces && dataset->supportsActiveFlag();
7,966✔
645

646
  if ( activeFaceFlag )
7,966✔
647
    activeBuffer.resize( bufLen );
424✔
648

649
  size_t i = 0;
7,966✔
650
  while ( i < dataset->valuesCount() )
22,081✔
651
  {
652
    size_t valsRead;
653
    if ( is3D )
14,122✔
654
    {
655
      if ( isVector )
850✔
656
      {
657
        valsRead = dataset->vectorVolumesData( i, bufLen, buffer.data() );
424✔
658
      }
659
      else
660
      {
661
        valsRead = dataset->scalarVolumesData( i, bufLen, buffer.data() );
426✔
662
      }
663
    }
664
    else
665
    {
666
      if ( isVector )
13,272✔
667
      {
668
        valsRead = dataset->vectorData( i, bufLen, buffer.data() );
3,255✔
669
      }
670
      else
671
      {
672
        valsRead = dataset->scalarData( i, bufLen, buffer.data() );
10,017✔
673
      }
674

675
      if ( activeFaceFlag )
13,272✔
676
        dataset->activeData( i, bufLen, activeBuffer.data() );
472✔
677
    }
678
    if ( valsRead == 0 )
14,122✔
679
      return ret;
7✔
680

681
    MDAL::Statistics dsStats = _calculateStatistics( buffer, valsRead, isVector, activeBuffer );
14,115✔
682
    combineStatistics( ret, dsStats );
14,115✔
683
    i += valsRead;
14,115✔
684
  }
685

686
  return ret;
7,959✔
687
}
7,966✔
688

689
void MDAL::combineStatistics( MDAL::Statistics &main, const MDAL::Statistics &other )
22,081✔
690
{
691
  if ( std::isnan( main.minimum ) ||
35,040✔
692
       ( !std::isnan( other.minimum ) && ( main.minimum > other.minimum ) ) )
12,959✔
693
  {
694
    main.minimum = other.minimum;
9,853✔
695
  }
696

697
  if ( std::isnan( main.maximum ) ||
35,040✔
698
       ( !std::isnan( other.maximum ) && ( main.maximum < other.maximum ) ) )
12,959✔
699
  {
700
    main.maximum = other.maximum;
13,408✔
701
  }
702
}
22,081✔
703

704
void MDAL::addBedElevationDatasetGroup( MDAL::Mesh *mesh, const Vertices &vertices )
132✔
705
{
706
  std::vector<double> values( mesh->verticesCount() );
132✔
707
  for ( size_t i = 0; i < vertices.size(); ++i )
196,394✔
708
  {
709
    values[i] = vertices[i].z;
196,262✔
710
  }
711
  addVertexScalarDatasetGroup( mesh, values, "Bed Elevation" );
132✔
712
}
132✔
713

714
static void _addScalarDatasetGroup( MDAL::Mesh *mesh,
159✔
715
                                    const std::vector<double> &values,
716
                                    const std::string &name,
717
                                    MDAL_DataLocation location
718
                                  )
719
{
720
  if ( !mesh )
159✔
721
    return;
1✔
722

723
  size_t maxCount = 0;
159✔
724
  switch ( location )
159✔
725
  {
726
    case MDAL_DataLocation::DataOnVertices: maxCount = mesh->verticesCount(); break;
137✔
727
    case MDAL_DataLocation::DataOnFaces: maxCount = mesh->facesCount(); break;
18✔
728
    case MDAL_DataLocation::DataOnEdges: maxCount = mesh->edgesCount(); break;
4✔
729
    default:
×
730
      assert( false );
×
731
  }
732

733
  if ( values.empty() )
159✔
734
    return;
1✔
735

736
  if ( maxCount == 0 )
158✔
737
    return;
×
738

739
  assert( values.size() ==  maxCount );
158✔
740

741
  std::shared_ptr<MDAL::DatasetGroup> group = std::make_shared< MDAL::DatasetGroup >(
742
        mesh->driverName(),
316✔
743
        mesh,
744
        mesh->uri(),
158✔
745
        name
746
      );
316✔
747
  group->setDataLocation( location );
158✔
748
  group->setIsScalar( true );
158✔
749

750
  std::shared_ptr<MDAL::MemoryDataset2D> dataset = std::make_shared< MDAL::MemoryDataset2D >( group.get() );
316✔
751
  dataset->setTime( 0.0 );
158✔
752
  memcpy( dataset->values(), values.data(), sizeof( double )*values.size() );
158✔
753
  dataset->setStatistics( MDAL::calculateStatistics( dataset ) );
158✔
754
  group->datasets.push_back( dataset );
158✔
755
  group->setStatistics( MDAL::calculateStatistics( group ) );
158✔
756
  mesh->datasetGroups.push_back( group );
158✔
757
}
758

759

760
void MDAL::addFaceScalarDatasetGroup( MDAL::Mesh *mesh,
18✔
761
                                      const std::vector<double> &values,
762
                                      const std::string &name )
763
{
764
  _addScalarDatasetGroup( mesh, values, name, MDAL_DataLocation::DataOnFaces );
18✔
765
}
18✔
766

767
void MDAL::addVertexScalarDatasetGroup( MDAL::Mesh *mesh, const std::vector<double> &values, const std::string &name )
137✔
768
{
769
  _addScalarDatasetGroup( mesh, values, name, MDAL_DataLocation::DataOnVertices );
137✔
770
}
137✔
771

772
void MDAL::addEdgeScalarDatasetGroup( MDAL::Mesh *mesh, const std::vector<double> &values, const std::string &name )
4✔
773
{
774
  _addScalarDatasetGroup( mesh, values, name, MDAL_DataLocation::DataOnEdges );
4✔
775
}
4✔
776

777
bool MDAL::isNativeLittleEndian()
519,023✔
778
{
779
  // https://stackoverflow.com/a/4181991/2838364
780
  int n = 1;
519,023✔
781
  return ( *( char * )&n == 1 );
519,023✔
782
}
783

784
std::string MDAL::coordinateToString( double coordinate, int precision )
2,472✔
785
{
786
  std::ostringstream oss;
2,472✔
787
  oss.setf( std::ios::fixed );
2,472✔
788
  if ( fabs( coordinate ) > 180 )
2,472✔
789
    oss.precision( precision ); //seems to not be a geographic coordinate, so 'precision' digits after the digital point
670✔
790
  else
791
    oss.precision( 6 + precision ); //could be a geographic coordinate, so 'precision'+6 digits after the digital point
1,802✔
792

793
  oss << coordinate;
2,472✔
794

795
  std::string returnString = oss.str();
2,472✔
796

797
  //remove unnecessary '0' or '.'
798
  if ( returnString.size() > 0 )
2,472✔
799
  {
800
    while ( '0' == returnString.back() )
13,014✔
801
    {
802
      returnString.pop_back();
10,542✔
803
    }
804

805
    if ( '.' == returnString.back() )
2,472✔
806
      returnString.pop_back();
1,348✔
807
  }
808

809
  return returnString;
4,944✔
810
}
2,472✔
811

812
std::string MDAL::doubleToString( double value, int precision )
7,162✔
813
{
814
  std::ostringstream oss;
7,162✔
815
  oss.precision( precision );
7,162✔
816
  oss << value;
7,162✔
817
  return oss.str();
14,324✔
818
}
7,162✔
819

820
std::string MDAL::prependZero( const std::string &str, size_t length )
6,360✔
821
{
822
  if ( length <= str.size() )
6,360✔
823
    return  str;
4,150✔
824

825
  return std::string( length - str.size(), '0' ).append( str );
4,420✔
826
}
827

828
MDAL::RelativeTimestamp::Unit MDAL::parseDurationTimeUnit( const std::string &timeUnit )
980✔
829
{
830
  MDAL::RelativeTimestamp::Unit unit = MDAL::RelativeTimestamp::hours; //default unit
980✔
831

832
  if ( timeUnit == "millisec" ||
1,960✔
833
       timeUnit == "msec" ||
1,960✔
834
       timeUnit == "millisecs" ||
2,940✔
835
       timeUnit == "msecs"
980✔
836
     )
837
  {
838
    unit = MDAL::RelativeTimestamp::milliseconds;
×
839
  }
840
  else if ( timeUnit == "second" ||
1,960✔
841
            timeUnit == "seconds" ||
1,826✔
842
            timeUnit == "Seconds" ||
1,659✔
843
            timeUnit == "sec" ||
1,626✔
844
            timeUnit == "secs" ||
1,626✔
845
            timeUnit == "s" ||
1,626✔
846
            timeUnit == "se" || // ascii_dat format
2,773✔
847
            timeUnit == "2" )  // ascii_dat format
803✔
848
  {
849
    unit = MDAL::RelativeTimestamp::seconds;
177✔
850
  }
851
  else if ( timeUnit == "minute" ||
1,606✔
852
            timeUnit == "minutes" ||
1,605✔
853
            timeUnit == "Minutes" ||
1,604✔
854
            timeUnit == "min" ||
1,604✔
855
            timeUnit == "mins" ||
1,604✔
856
            timeUnit == "mi" || // ascii_dat format
2,408✔
857
            timeUnit == "1" ) // ascii_dat format
802✔
858
  {
859
    unit = MDAL::RelativeTimestamp::minutes;
3✔
860
  }
861
  else if ( timeUnit == "day" ||
1,600✔
862
            timeUnit == "days" ||
1,600✔
863
            timeUnit == "Days" )
797✔
864
  {
865
    unit = MDAL::RelativeTimestamp::days;
6✔
866
  }
867
  else if ( timeUnit == "week" ||
1,588✔
868
            timeUnit == "weeks" )
794✔
869
  {
870
    unit = MDAL::RelativeTimestamp::weeks;
1✔
871
  }
872

873

874
  return unit;
980✔
875
}
876

877
MDAL::RelativeTimestamp::Unit MDAL::parseCFTimeUnit( std::string timeInformation )
235✔
878
{
879
  auto strings = MDAL::split( timeInformation, ' ' );
235✔
880
  if ( strings.size() < 3 )
235✔
881
    return MDAL::RelativeTimestamp::hours; //default value
6✔
882

883
  if ( strings[1] == "since" )
229✔
884
  {
885
    std::string timeUnit = strings[0];
229✔
886
    if ( timeUnit == "month" ||
457✔
887
         timeUnit == "months" ||
455✔
888
         timeUnit == "mon" ||
684✔
889
         timeUnit == "mons" )
227✔
890
    {
891
      return MDAL::RelativeTimestamp::months_CF;
2✔
892
    }
893
    else if ( timeUnit == "year" ||
453✔
894
              timeUnit == "years" ||
452✔
895
              timeUnit == "yr" ||
679✔
896
              timeUnit == "yrs" )
226✔
897
    {
898
      return MDAL::RelativeTimestamp::exact_years;
1✔
899
    }
900

901
    return MDAL::parseDurationTimeUnit( strings[0] );
226✔
902
  }
229✔
903

904
  return MDAL::RelativeTimestamp::hours;//default value
×
905
}
235✔
906

907
MDAL::DateTime MDAL::parseCFReferenceTime( const std::string &timeInformation, const std::string &calendarString )
47✔
908
{
909
  auto strings = MDAL::split( timeInformation, ' ' );
47✔
910
  if ( strings.size() < 3 )
47✔
911
    return MDAL::DateTime();
6✔
912

913
  if ( strings[1] != "since" )
41✔
914
    return MDAL::DateTime();
×
915

916
  std::string dateString = strings[2];
41✔
917

918
  auto dateStringValues = MDAL::split( dateString, '-' );
41✔
919
  if ( dateStringValues.size() != 3 )
41✔
920
    return MDAL::DateTime();
×
921

922
  int year = MDAL::toInt( dateStringValues[0] );
41✔
923
  int month = MDAL::toInt( dateStringValues[1] );
41✔
924
  int day = MDAL::toInt( dateStringValues[2] );
41✔
925

926
  int hours = 0;
41✔
927
  int minutes = 0;
41✔
928
  double seconds = 0;
41✔
929

930
  if ( strings.size() > 3 )
41✔
931
  {
932
    std::string timeString = strings[3];
40✔
933
    auto timeStringsValue = MDAL::split( timeString, ":" );
80✔
934
    if ( timeStringsValue.size() == 3 )
40✔
935
    {
936
      hours = MDAL::toInt( timeStringsValue[0] );
39✔
937
      minutes = MDAL::toInt( timeStringsValue[1] );
39✔
938
      seconds = MDAL::toDouble( timeStringsValue[2] );
39✔
939
    }
940
  }
40✔
941

942
  MDAL::DateTime::Calendar calendar;
943
  if ( calendarString == "gregorian" || calendarString == "standard" || calendarString.empty() )
41✔
944
    calendar = MDAL::DateTime::Gregorian;
39✔
945
  else if ( calendarString == "proleptic_gregorian" )
2✔
946
    calendar = MDAL::DateTime::ProlepticGregorian;
2✔
947
  else if ( calendarString == "julian" )
×
948
    calendar = MDAL::DateTime::Julian;
×
949
  else
950
    return MDAL::DateTime();
×
951

952
  return MDAL::DateTime( year, month, day, hours, minutes, seconds, calendar );
41✔
953
}
47✔
954

955
bool MDAL::getHeaderLine( std::ifstream &stream, std::string &line )
731✔
956
{
957
  if ( !stream.is_open() ) return false;
731✔
958
  char b[100] = "";
731✔
959
  if ( ! stream.get( b, sizeof( b ) - 1, '\n' ) ) return false;
731✔
960
  line = std::string( b );
722✔
961
  return true;
722✔
962
}
963

964
MDAL::Error::Error( MDAL_Status status, std::string message, std::string driverName ): status( status ), mssg( message ), driver( driverName ) {}
607✔
965

966
void MDAL::Error::setDriver( std::string driverName )
4✔
967
{
968
  driver = driverName;
4✔
969
}
4✔
970

971
void MDAL::parseDriverFromUri( const std::string &uri, std::string &driver )
396✔
972
{
973
  bool hasDriverSet = ( uri.find( ":\"" ) != std::string::npos );
396✔
974
  driver = "";
396✔
975

976
  if ( !hasDriverSet )
396✔
977
    return;
354✔
978

979
  driver = MDAL::split( uri, ":\"" )[0];
42✔
980
}
981

982
void MDAL::parseMeshFileFromUri( const std::string &uri, std::string &meshFile )
396✔
983
{
984
  bool hasDriverSet = ( uri.find( ":\"" ) != std::string::npos );
396✔
985
  bool hasSpecificMeshSet = ( uri.find( "\":" ) != std::string::npos );
396✔
986
  meshFile = "";
396✔
987

988
  if ( !hasDriverSet && !hasSpecificMeshSet )
396✔
989
    meshFile = MDAL::trim( uri, "\"" );
349✔
990
  else if ( hasDriverSet && hasSpecificMeshSet )
47✔
991
  {
992
    std::string token = MDAL::split( uri, ":\"" )[1]; // split from driver
18✔
993
    token = MDAL::split( token, "\":" )[0]; // split from specific mesh
9✔
994
    meshFile = MDAL::trim( token, "\"" );
9✔
995
  }
9✔
996
  else if ( hasDriverSet )
38✔
997
  {
998
    std::string token = MDAL::split( uri, ":\"" )[1]; // split from driver
66✔
999
    meshFile = MDAL::trim( token, "\"" );
33✔
1000
  }
33✔
1001
  else if ( hasSpecificMeshSet )
5✔
1002
  {
1003
    std::string token = MDAL::split( uri, "\":" )[0]; // split from specific mesh
10✔
1004
    meshFile = MDAL::trim( token, "\"" );
5✔
1005
  }
5✔
1006
}
396✔
1007

1008
void parseSpecificMeshFromUri( const std::string &uri, std::string &meshName )
242✔
1009
{
1010
  bool hasSpecificMeshSet = ( uri.find( "\":" ) != std::string::npos );
242✔
1011
  meshName = "";
242✔
1012

1013
  if ( !hasSpecificMeshSet )
242✔
1014
    return;
228✔
1015

1016
  std::vector<std::string> tokens = MDAL::split( uri, "\":" );
28✔
1017
  if ( tokens.size() > 1 )
14✔
1018
  {
1019
    meshName = MDAL::trim( tokens.at( 1 ), "\"" );
14✔
1020
  }
1021
}
14✔
1022

1023
void MDAL::parseDriverAndMeshFromUri( const std::string &uri, std::string &driver, std::string &meshFile, std::string &meshName )
242✔
1024
{
1025
  parseDriverFromUri( uri, driver );
242✔
1026
  parseMeshFileFromUri( uri, meshFile );
242✔
1027
  parseSpecificMeshFromUri( uri, meshName );
242✔
1028
}
242✔
1029

1030
std::string MDAL::buildMeshUri( const std::string &meshFile, const std::string &meshName, const std::string &driver )
208✔
1031
{
1032
  if ( meshFile.empty() )
208✔
1033
    return std::string();
1✔
1034

1035
  std::string uri( "" );
207✔
1036

1037
  bool hasDriverName = !driver.empty();
207✔
1038
  bool hasMeshName = !meshName.empty();
207✔
1039

1040
  if ( hasDriverName && hasMeshName )
207✔
1041
    uri = driver + ":\"" + meshFile + "\":" + meshName;
46✔
1042
  else if ( !hasDriverName && !hasMeshName )
161✔
1043
    uri = meshFile;
1✔
1044
  else if ( hasDriverName ) // only driver
160✔
1045
    uri = driver + ":\"" + meshFile + "\"";
156✔
1046
  else if ( hasMeshName ) // only mesh name
4✔
1047
    uri = "\"" + meshFile + "\":" + meshName;
4✔
1048

1049
  return uri;
207✔
1050
}
207✔
1051

1052
std::string MDAL::buildAndMergeMeshUris( const std::string &meshFile, const std::vector<std::string> &meshNames, const std::string &driver )
33✔
1053
{
1054
  std::string mergedUris;
33✔
1055
  size_t meshNamesCount = meshNames.size();
33✔
1056

1057
  for ( size_t i = 0; i < meshNamesCount; ++i )
72✔
1058
  {
1059
    mergedUris += buildMeshUri( meshFile, meshNames.at( i ), driver );
39✔
1060

1061
    if ( ( i + 1 ) < meshNamesCount ) // If this is not the last mesh in array, add separator
39✔
1062
      mergedUris += ";;";
7✔
1063
  }
1064

1065
  if ( meshNamesCount == 0 )
33✔
1066
    mergedUris = buildMeshUri( meshFile, "", driver );
1✔
1067

1068
  return mergedUris;
33✔
1069
}
×
1070

1071
MDAL::Library::Library( std::string libraryFile )
2✔
1072
{
1073
  d = new Data;
2✔
1074
  d->mLibraryFile = libraryFile;
2✔
1075
  d->mRef++;
2✔
1076
}
2✔
1077

1078
MDAL::Library::~Library()
53✔
1079
{
1080
  d->mRef--;
53✔
1081
#ifdef _WIN32
1082
  if ( d->mLibrary &&  d->mRef == 0 )
1083
    FreeLibrary( d->mLibrary );
1084
#else
1085
  if ( d->mLibrary &&  d->mRef == 0 )
53✔
1086
    dlclose( d->mLibrary );
×
1087
#endif
1088
}
53✔
1089

1090
MDAL::Library::Library( const MDAL::Library &other )
51✔
1091
{
1092
  *this = other;
51✔
1093
  d->mRef++;
51✔
1094
}
51✔
1095

1096
MDAL::Library &MDAL::Library::operator=( const MDAL::Library &other )
51✔
1097
{
1098
  d = other.d;
51✔
1099
  d->mRef++;
51✔
1100

1101
  return ( *this );
51✔
1102
}
1103

1104
bool MDAL::Library::isValid()
117✔
1105
{
1106
  if ( !d->mLibrary )
117✔
1107
    loadLibrary();
3✔
1108

1109
  return d->mLibrary != nullptr;
117✔
1110
}
1111

1112
std::vector<std::string> MDAL::Library::libraryFilesInDir( const std::string &dirPath )
1✔
1113
{
1114
  std::vector<std::string> filesList;
1✔
1115
#ifdef _WIN32
1116
  WIN32_FIND_DATA data;
1117
  HANDLE hFind;
1118
  std::string pattern = dirPath;
1119
  pattern.push_back( '*' );
1120

1121
  hFind = FindFirstFile( pattern.c_str(), &data );
1122

1123
  if ( hFind == INVALID_HANDLE_VALUE )
1124
    return filesList;
1125

1126
  do
1127
  {
1128
    std::string fileName( data.cFileName );
1129
    if ( !fileName.empty() && fileExtension( fileName ) == ".dll" )
1130
      filesList.push_back( fileName );
1131
  }
1132
  while ( FindNextFile( hFind, &data ) != 0 );
1133

1134
  FindClose( hFind );
1135
#else
1136
  DIR *dir = opendir( dirPath.c_str() );
1✔
1137
  struct dirent *de = readdir( dir );
1✔
1138
  while ( de != nullptr )
8✔
1139
  {
1140
    std::string fileName( de->d_name );
7✔
1141
    if ( !fileName.empty() )
7✔
1142
    {
1143
      std::string extentsion = fileExtension( fileName );
7✔
1144
      if ( extentsion == ".so" || extentsion == ".dylib" )
7✔
1145
        filesList.push_back( fileName );
1✔
1146
    }
7✔
1147
    de = readdir( dir );
7✔
1148
  }
7✔
1149

1150
  closedir( dir );
1✔
1151
#endif
1152
  return filesList;
1✔
1153
}
×
1154

1155
bool MDAL::Library::loadLibrary()
3✔
1156
{
1157
  //should we allow only one successful loading?
1158
  if ( d->mLibrary )
3✔
1159
    return false;
×
1160
#ifdef _WIN32
1161
  UINT uOldErrorMode =
1162
    SetErrorMode( SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS );
1163
  d->mLibrary = LoadLibrary( d->mLibraryFile.c_str() );
1164
  SetErrorMode( uOldErrorMode );
1165
#else
1166
  d->mLibrary = dlopen( d->mLibraryFile.c_str(), RTLD_LAZY );
3✔
1167
#endif
1168

1169
  return d->mLibrary != nullptr;
3✔
1170
}
1171

STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc