1 /*
2 MDAL - Mesh Data Abstraction Library (MIT License)
3 Copyright (C) 2020 Runette Software Ltd.
4 */
5
6 #include <stddef.h>
7 #include <iosfwd>
8 #include <iostream>
9 #include <fstream>
10 #include <sstream>
11 #include <string>
12 #include <memory>
13 #include <vector>
14 #include <map>
15 #include <cassert>
16 #include <limits>
17 #include <algorithm>
18 #include <string.h>
19
20 #include "mdal_ply.hpp"
21 #include "mdal.h"
22 #include "mdal_utils.hpp"
23 #include "mdal_logger.hpp"
24 #include "mdal_data_model.hpp"
25 #include "mdal_memory_data_model.hpp"
26 #include "libplyxx.h"
27 #include "mdal_driver_manager.hpp"
28
29 #define DRIVER_NAME "PLY"
30
DriverPly()31 MDAL::DriverPly::DriverPly() :
32 Driver( DRIVER_NAME,
33 "Stanford PLY Ascii Mesh File",
34 "*.ply",
35 Capability::ReadMesh |
36 Capability::SaveMesh |
37 Capability::WriteDatasetsOnVertices |
38 Capability::WriteDatasetsOnFaces |
39 Capability::WriteDatasetsOnEdges |
40 Capability::WriteDatasetsOnVolumes
41 )
42 {
43 }
44
create()45 MDAL::DriverPly *MDAL::DriverPly::create()
46 {
47 return new DriverPly();
48 }
49
50 MDAL::DriverPly::~DriverPly() = default;
51
getIndex(std::vector<std::pair<std::string,bool>> v,std::string in)52 size_t getIndex( std::vector<std::pair<std::string, bool>> v, std::string in )
53 {
54 auto is_equal = [ in ]( std::pair<std::string, bool> s ) { return s.first == in; };
55
56 auto it = std::find_if( v.begin(), v.end(), is_equal );
57 return ( size_t )std::distance( v.begin(), it );
58 }
59
60 // check for the magic number which in a PLY file is "ply"
canReadMesh(const std::string & uri)61 bool MDAL::DriverPly::canReadMesh( const std::string &uri )
62 {
63 std::ifstream in( uri, std::ifstream::in );
64 std::string line;
65 if ( !MDAL::getHeaderLine( in, line ) || !startsWith( line, "ply" ) )
66 {
67 return false;
68 }
69 return true;
70 }
71
saveMeshOnFileSuffix() const72 std::string MDAL::DriverPly::saveMeshOnFileSuffix() const
73 {
74 return "ply";
75 }
76
load(const std::string & meshFile,const std::string &)77 std::unique_ptr<MDAL::Mesh> MDAL::DriverPly::load( const std::string &meshFile, const std::string & )
78 {
79 MDAL::Log::resetLastStatus();
80 Vertices vertices( 0 );
81 Faces faces( 0 );
82 Edges edges( 0 );
83 size_t maxSizeFace = 0;
84
85 size_t vertexCount = 0;
86 size_t faceCount = 0;
87 size_t edgeCount = 0;
88
89 //data structures that will contain all of the datasets, categorised by vertex, face and edge datasets
90 std::vector<std::vector<double>> vertexDatasets; // contains the data
91 std::vector<std::pair<std::string, bool>> vProp2Ds; // contains the dataset name and a flag for scalar / vector
92 std::vector<std::vector<double>> faceDatasets;
93 std::vector<std::pair<std::string, bool>> fProp2Ds;
94 std::vector<std::vector<double>> edgeDatasets;
95 std::vector<std::pair<std::string, bool>> eProp2Ds;
96 std::unordered_map<std::string, std::pair<std::vector<double>, std::vector<int>>> listProps; // contains the list datasets as vector of values and vector indices for each face into the vector of values
97
98 libply::File file( meshFile );
99 if ( MDAL::Log::getLastStatus() != MDAL_Status::None ) { return nullptr; }
100 const libply::ElementsDefinition &definitions = file.definitions();
101 const libply::Metadata &metadata = file.metadata();
102 for ( const libply::Element &element : definitions )
103 {
104 if ( element.name == "vertex" )
105 {
106 vertexCount = element.size;
107 }
108 else if ( element.name == "face" )
109 {
110 faceCount = element.size;
111 }
112 else if ( element.name == "edge" )
113 {
114 edgeCount = element.size;
115 }
116 for ( const libply::Property &property : element.properties )
117 {
118 if ( element.name == "vertex" &&
119 property.name != "X" &&
120 property.name != "x" &&
121 property.name != "Y" &&
122 property.name != "y" &&
123 property.name != "Z" &&
124 property.name != "z"
125 )
126 {
127 vProp2Ds.emplace_back( property.name, property.isList );
128 vertexDatasets.push_back( std::vector<double>() );
129 if ( property.isList ) listProps.emplace( property.name, std::make_pair( std::vector<double>(), std::vector<int>() ) );
130 }
131 else if ( element.name == "face" &&
132 property.name != "vertex_indices"
133 )
134 {
135 fProp2Ds.emplace_back( property.name, property.isList );
136 faceDatasets.push_back( std::vector<double>() );
137 if ( property.isList ) listProps.emplace( property.name, std::make_pair( std::vector<double>(), std::vector<int>() ) );
138 }
139 else if ( element.name == "edge" &&
140 property.name != "vertex1" &&
141 property.name != "vertex2"
142 )
143 {
144 eProp2Ds.emplace_back( property.name, property.isList );
145 edgeDatasets.push_back( std::vector<double>() );
146 if ( property.isList ) listProps.emplace( property.name, std::make_pair( std::vector<double>(), std::vector<int>() ) );
147 }
148 }
149 }
150
151
152
153 for ( const libply::Element &el : definitions )
154 {
155 if ( el.name == "vertex" )
156 {
157 libply::ElementReadCallback vertexCallback = [&vertices, &el, &vProp2Ds, &vertexDatasets, &listProps]( libply::ElementBuffer & e )
158 {
159 Vertex vertex;
160 for ( size_t i = 0; i < el.properties.size(); i++ )
161 {
162 libply::Property p = el.properties[i];
163 if ( p.name == "X" || p.name == "x" )
164 {
165 vertex.x = e[i];
166 }
167 else if ( p.name == "Y" || p.name == "y" )
168 {
169 vertex.y = e[i];
170 }
171 else if ( p.name == "Z" || p.name == "z" )
172 {
173 vertex.z = e[i];
174 }
175 else
176 {
177 int dsIdx = getIndex( vProp2Ds, p.name );
178 if ( vProp2Ds[ dsIdx ].second )
179 {
180 const std::string name = vProp2Ds[ dsIdx ].first;
181 auto &vals = listProps.at( name );
182 libply::ListProperty *lp = dynamic_cast<libply::ListProperty *>( &e[i] );
183 vals.second.push_back( lp->size() );
184 for ( size_t j = 0; j < lp->size(); j++ )
185 {
186 vals.first.push_back( lp->value( j ) );
187 }
188 }
189 else
190 {
191 std::vector<double> &ds = vertexDatasets[dsIdx];
192 ds.push_back( e[i] );
193 }
194 }
195 }
196 vertices.push_back( vertex );
197 };
198 file.setElementReadCallback( "vertex", vertexCallback );
199 }
200 else if ( el.name == "face" )
201 {
202 libply::ElementReadCallback faceCallback = [&faces, &el, &maxSizeFace, &fProp2Ds, &faceDatasets, &listProps]( libply::ElementBuffer & e )
203 {
204 Face face;
205 for ( size_t i = 0; i < el.properties.size(); i++ )
206 {
207 libply::Property p = el.properties[i];
208 if ( p.name == "vertex_indices" )
209 {
210 if ( !p.isList )
211 {
212 MDAL::Log::error( MDAL_Status::Err_InvalidData, "PLY: the triangles are not a list" );
213 }
214 else
215 {
216 libply::ListProperty *lp = dynamic_cast<libply::ListProperty *>( &e[i] );
217 if ( maxSizeFace < lp->size() ) maxSizeFace = lp->size();
218 face.resize( lp->size() );
219 for ( size_t j = 0; j < lp->size(); j++ )
220 {
221 face[j] = int( lp->value( j ) );
222 }
223 }
224 }
225 else
226 {
227 int dsIdx = getIndex( fProp2Ds, p.name );
228 if ( fProp2Ds[ dsIdx ].second )
229 {
230 const std::string name = fProp2Ds[ dsIdx ].first;
231 auto &vals = listProps.at( name );
232 libply::ListProperty *lp = dynamic_cast<libply::ListProperty *>( &e[i] );
233 vals.second.push_back( lp->size() );
234 for ( size_t j = 0; j < lp->size(); j++ )
235 {
236 vals.first.push_back( lp->value( j ) );
237 }
238 }
239 else
240 {
241 std::vector<double> &ds = faceDatasets[dsIdx];
242 ds.push_back( e[i] );
243 }
244 }
245 }
246 faces.push_back( face );
247 };
248 file.setElementReadCallback( "face", faceCallback );
249 }
250 else if ( el.name == "edge" )
251 {
252 libply::ElementReadCallback edgeCallback = [&edges, &el, &eProp2Ds, &edgeDatasets, &listProps]( libply::ElementBuffer & e )
253 {
254 Edge edge;
255 for ( size_t i = 0; i < el.properties.size(); i++ )
256 {
257 libply::Property p = el.properties[i];
258 if ( p.name == "vertex1" )
259 {
260 edge.startVertex = int( e[i] );
261 }
262 else if ( p.name == "vertex2" )
263 {
264 edge.endVertex = int( e[i] );
265 }
266 else
267 {
268 int dsIdx = getIndex( eProp2Ds, p.name );
269 if ( eProp2Ds[ dsIdx ].second )
270 {
271 const std::string name = eProp2Ds[ dsIdx ].first;
272 auto &vals = listProps.at( name );
273 libply::ListProperty *lp = dynamic_cast<libply::ListProperty *>( &e[i] );
274 vals.second.push_back( lp->size() );
275 for ( size_t j = 0; j < lp->size(); j++ )
276 {
277 vals.first.push_back( lp->value( j ) );
278 }
279 }
280 else
281 {
282 std::vector<double> &ds = edgeDatasets[dsIdx];
283 ds.push_back( e[i] );
284 }
285 }
286 }
287 edges.push_back( edge );
288 };
289 file.setElementReadCallback( "edge", edgeCallback );
290 }
291 }
292
293 file.read();
294 if ( MDAL::Log::getLastStatus() != MDAL_Status::None ) { return nullptr; }
295 if ( vertices.size() != vertexCount ||
296 faces.size() != faceCount ||
297 edges.size() != edgeCount
298 )
299 {
300 MDAL_SetStatus( MDAL_LogLevel::Error, MDAL_Status::Err_InvalidData, "Incomplete Mesh" );
301 return nullptr;
302 }
303
304 std::unique_ptr< MemoryMesh > mesh(
305 new MemoryMesh(
306 DRIVER_NAME,
307 maxSizeFace,
308 meshFile
309 )
310 );
311 mesh->setFaces( std::move( faces ) );
312 mesh->setVertices( std::move( vertices ) );
313 mesh->setEdges( std::move( edges ) );
314 if ( metadata.find( "crs" ) != metadata.end() )
315 {
316 mesh->setSourceCrs( metadata.at( "crs" ) );
317 }
318
319
320 // Add Bed Elevation
321 MDAL::addBedElevationDatasetGroup( mesh.get(), mesh->vertices() );
322
323 // Add Vertex Datasets
324 for ( size_t i = 0; i < vertexDatasets.size(); ++i )
325 {
326 if ( vProp2Ds[i].second )
327 {
328 auto &vals = listProps.at( vProp2Ds[i].first );
329 vertexDatasets[i].clear();
330 auto it = vals.second.begin();
331 size_t idx = 0;
332 while ( idx < vals.first.size() )
333 {
334 vertexDatasets[i].push_back( vals.first[idx] );
335 vertexDatasets[i].push_back( vals.first[idx + 1] );
336 idx += *it;
337 it = std::next( it, 1 );
338 }
339 listProps.erase( vProp2Ds[i].first );
340 }
341 std::shared_ptr<DatasetGroup> group = addDatasetGroup( mesh.get(), vProp2Ds[i].first, DataOnVertices, !vProp2Ds[i].second );
342 addDataset2D( group.get(), vertexDatasets[i] );
343 }
344
345 //Add face datasets and volume datasets
346 for ( size_t i = 0; i < faceDatasets.size(); ++i )
347 {
348 if ( fProp2Ds[i].second )
349 {
350 std::string name = fProp2Ds[i].first;
351 if ( name.find( "__vols" ) != std::string::npos ) break;
352 auto &vals = listProps.at( name );
353 faceDatasets[i].clear();
354 auto it = vals.second.begin();
355 size_t idx = 0;
356 if ( listProps.find( name + "__vols" ) == listProps.end() )
357 {
358 while ( idx < vals.first.size() )
359 {
360 faceDatasets[i].push_back( vals.first[idx] );
361 faceDatasets[i].push_back( vals.first[idx + 1] );
362 idx += *it;
363 it = std::next( it, 1 );
364 }
365 std::shared_ptr<DatasetGroup> group = addDatasetGroup( mesh.get(), name, DataOnFaces, false );
366 addDataset2D( group.get(), faceDatasets[i] );
367 }
368 else
369 {
370 auto levels = listProps.at( name + "__vols" );
371 std::shared_ptr<DatasetGroup> group = addDatasetGroup( mesh.get(), name, DataOnVolumes, true );
372 addDataset3D( group.get(), vals.first, vals.second, levels.first, levels.second );
373 listProps.erase( name + "__vols" );
374 }
375 listProps.erase( name );
376 }
377 else
378 {
379 std::shared_ptr<DatasetGroup> group = addDatasetGroup( mesh.get(), fProp2Ds[i].first, DataOnFaces, true );
380 addDataset2D( group.get(), faceDatasets[i] );
381 }
382 }
383
384 // Add Edge Datasets
385 for ( size_t i = 0; i < edgeDatasets.size(); ++i )
386 {
387 if ( eProp2Ds[i].second )
388 {
389 auto vals = listProps.at( eProp2Ds[i].first );
390 edgeDatasets[i].clear();
391 auto it = vals.second.begin();
392 size_t idx = 0;
393 while ( idx < vals.first.size() )
394 {
395 edgeDatasets[i].push_back( vals.first[idx] );
396 edgeDatasets[i].push_back( vals.first[idx + 1] );
397 idx += *it;
398 it = std::next( it, 1 );
399 }
400 listProps.erase( eProp2Ds[i].first );
401 }
402 std::shared_ptr<DatasetGroup> group = addDatasetGroup( mesh.get(), eProp2Ds[i].first, DataOnEdges, !eProp2Ds[i].second );
403 addDataset2D( group.get(), edgeDatasets[i] );
404 }
405
406 /*
407 * Clean up
408 */
409 for ( size_t i = 0; i < vertexDatasets.size(); ++i )
410 {
411 vertexDatasets.pop_back();
412 };
413
414 for ( size_t i = 0; i < faceDatasets.size(); ++i )
415 {
416 faceDatasets.pop_back();
417 };
418
419 for ( size_t i = 0; i < edgeDatasets.size(); ++i )
420 {
421 edgeDatasets.pop_back();
422 };
423
424 return std::unique_ptr<Mesh>( mesh.release() );
425
426 }
427
addDatasetGroup(MDAL::Mesh * mesh,const std::string & name,const MDAL_DataLocation location,bool isScalar)428 std::shared_ptr< MDAL::DatasetGroup> MDAL::DriverPly::addDatasetGroup( MDAL::Mesh *mesh, const std::string &name, const MDAL_DataLocation location, bool isScalar )
429 {
430 if ( !mesh )
431 return NULL;
432
433 if ( location == DataOnFaces && mesh->facesCount() == 0 )
434 return NULL;
435
436 if ( location == DataOnEdges && mesh->edgesCount() == 0 )
437 return NULL;
438
439 std::shared_ptr< DatasetGroup > group = std::make_shared< DatasetGroup >( mesh->driverName(), mesh, name, name );
440 group->setDataLocation( location );
441 group->setIsScalar( isScalar );
442 group->setStatistics( MDAL::calculateStatistics( group ) );
443 mesh->datasetGroups.push_back( group );
444 return group;
445 }
446
addDataset2D(MDAL::DatasetGroup * group,const std::vector<double> & values)447 void MDAL::DriverPly::addDataset2D( MDAL::DatasetGroup *group, const std::vector<double> &values )
448 {
449 if ( !group )
450 return;
451
452 size_t mult = 1;
453 if ( !group->isScalar() ) mult = 2;
454
455 MDAL::Mesh *mesh = group->mesh();
456
457 if ( values.empty() )
458 return;
459
460 if ( 0 == mesh->verticesCount() )
461 return;
462
463 if ( group->dataLocation() == DataOnVertices )
464 {
465 if ( values.size() != mesh->verticesCount()*mult )
466 {
467 MDAL_SetStatus( MDAL_LogLevel::Error, MDAL_Status::Err_InvalidData, "PLY: Invalid Number of Data Values" );
468 return;
469 }
470 }
471
472 if ( group->dataLocation() == DataOnFaces )
473 {
474 if ( values.size() != mesh->facesCount()*mult )
475 {
476 MDAL_SetStatus( MDAL_LogLevel::Error, MDAL_Status::Err_InvalidData, "PLY: Invalid Number of Data Values" );
477 return;
478 }
479 if ( mesh->facesCount() == 0 )
480 return;
481 }
482
483 if ( group->dataLocation() == DataOnEdges )
484 {
485 if ( values.size() != mesh->edgesCount()*mult )
486 {
487 MDAL_SetStatus( MDAL_LogLevel::Error, MDAL_Status::Err_InvalidData, "PLY: Invalid Number of Data Values" );
488 return;
489 }
490 if ( mesh->edgesCount() == 0 )
491 return;
492 }
493
494 std::shared_ptr< MDAL::MemoryDataset2D > dataset = std::make_shared< MemoryDataset2D >( group );
495 dataset->setTime( 0.0 );
496 memcpy( dataset->values(), values.data(), sizeof( double ) * values.size() );
497 dataset->setStatistics( MDAL::calculateStatistics( dataset ) );
498 group->datasets.push_back( dataset );
499 group->setStatistics( MDAL::calculateStatistics( group ) );
500 }
501
addDataset3D(MDAL::DatasetGroup * group,const std::vector<double> & values,const std::vector<int> & valueIndexes,const std::vector<double> & levels,const std::vector<int> & levelIndexes)502 void MDAL::DriverPly::addDataset3D( MDAL::DatasetGroup *group,
503 const std::vector<double> &values,
504 const std::vector<int> &valueIndexes,
505 const std::vector<double> &levels,
506 const std::vector<int> &levelIndexes )
507 {
508 if ( !group )
509 return;
510
511
512 MDAL::Mesh *mesh = group->mesh();
513
514 if ( values.empty() )
515 return;
516
517 if ( 0 == mesh->facesCount() )
518 return;
519
520 if ( valueIndexes.size() != mesh->facesCount() ||
521 levelIndexes.size() != mesh->facesCount() ||
522 levels.size() != values.size() + mesh->facesCount()
523 )
524 {
525 MDAL_SetStatus( MDAL_LogLevel::Error, MDAL_Status::Err_InvalidData, "Incomplete Volume Dataset" );
526 return;
527 }
528
529 int maxVerticalLevelCount = * std::max_element( valueIndexes.begin(), valueIndexes.end() );
530
531 std::shared_ptr< MDAL::MemoryDataset3D > dataset = std::make_shared< MemoryDataset3D >( group, values.size(), maxVerticalLevelCount, valueIndexes.data(), levels.data() );
532 dataset->setTime( 0.0 );
533 memcpy( dataset->values(), values.data(), sizeof( double ) * values.size() );
534 dataset->setStatistics( MDAL::calculateStatistics( dataset ) );
535 group->datasets.push_back( dataset );
536 group->setStatistics( MDAL::calculateStatistics( group ) );
537 }
538
save(const std::string & fileName,const std::string & meshName,Mesh * mesh)539 void MDAL::DriverPly::save( const std::string &fileName, const std::string &meshName, Mesh *mesh )
540 {
541 MDAL_UNUSED( meshName );
542
543 MDAL::Log::resetLastStatus();
544
545 DatasetGroups groups = mesh->datasetGroups;
546
547 // vectors to hold the different types of group
548 DatasetGroups vgroups;
549 DatasetGroups fgroups;
550 DatasetGroups egroups;
551 DatasetGroups volGroups;
552
553 for ( std::shared_ptr<DatasetGroup> group : groups )
554 {
555 if ( group->dataLocation() == MDAL_DataLocation::DataOnVertices )
556 {
557 if ( group->name() != "Bed Elevation" ) vgroups.push_back( group );
558 }
559 else if ( group->dataLocation() == MDAL_DataLocation::DataOnFaces )
560 {
561 fgroups.push_back( group );
562 }
563 else if ( group->dataLocation() == MDAL_DataLocation::DataOnEdges )
564 {
565 egroups.push_back( group );
566 }
567 else if ( group->dataLocation() == MDAL_DataLocation::DataOnVolumes )
568 {
569 if ( group->isScalar() )
570 {
571 volGroups.push_back( group );
572 }
573 else
574 {
575 MDAL_SetStatus( MDAL_LogLevel::Warn, MDAL_Status::Err_IncompatibleDatasetGroup, "PLY: Vector Datasets on Volumes are not supported" );
576 }
577 }
578 }
579
580
581 libply::FileOut file( fileName, libply::File::Format::ASCII );
582 if ( MDAL::Log::getLastStatus() != MDAL_Status::None ) return;
583
584 libply::ElementsDefinition definitions;
585 std::vector<libply::Property> vproperties;
586 vproperties.emplace_back( "X", libply::Type::COORDINATE, false );
587 vproperties.emplace_back( "Y", libply::Type::COORDINATE, false );
588 vproperties.emplace_back( "Z", libply::Type::COORDINATE, false );
589 for ( std::shared_ptr<DatasetGroup> group : vgroups )
590 {
591 vproperties.emplace_back( group->name(), libply::Type::FLOAT64, ! group->isScalar() );
592 }
593
594 definitions.emplace_back( "vertex", mesh->verticesCount(), vproperties );
595 if ( mesh->facesCount() > 0 )
596 {
597 std::vector<libply::Property> fproperties;
598 fproperties.emplace_back( "vertex_indices", libply::Type::UINT32, true );
599 for ( std::shared_ptr<DatasetGroup> group : fgroups )
600 {
601 fproperties.emplace_back( group->name(), libply::Type::FLOAT64, ! group->isScalar() );
602 }
603 for ( std::shared_ptr<DatasetGroup> group : volGroups )
604 {
605 fproperties.emplace_back( group->name(), libply::Type::FLOAT64, true );
606 fproperties.emplace_back( group->name() + "__vols", libply::Type::FLOAT64, true );
607 }
608 definitions.emplace_back( "face", mesh->facesCount(), fproperties );
609 }
610
611 if ( mesh->edgesCount() > 0 )
612 {
613 std::vector<libply::Property> eproperties;
614 eproperties.emplace_back( "vertex1", libply::Type::UINT32, false );
615 eproperties.emplace_back( "vertex2", libply::Type::UINT32, false );
616 for ( std::shared_ptr<DatasetGroup> group : egroups )
617 {
618 eproperties.emplace_back( group->name(), libply::Type::FLOAT64, ! group->isScalar() );
619 }
620 definitions.emplace_back( "edge", mesh->edgesCount(), eproperties );
621 }
622 file.setElementsDefinition( definitions );
623
624 // write vertices
625 std::unique_ptr<MDAL::MeshVertexIterator> vertices = mesh->readVertices();
626
627
628 libply::ElementWriteCallback vertexCallback = [&vertices, &vgroups]( libply::ElementBuffer & e, size_t index )
629 {
630 double vertex[3];
631 vertices->next( 1, vertex );
632 e[0] = vertex[0];
633 e[1] = vertex[1];
634 e[2] = vertex[2];
635 for ( size_t i = 0; i < vgroups.size(); i++ )
636 {
637 if ( vgroups[i]->isScalar() )
638 {
639 double val[1];
640 vgroups[i]->datasets[0]->scalarData( index, 1, &val[0] );
641 e[i + 3] = val[0];
642 }
643 else
644 {
645 double val[2];
646 vgroups[i]->datasets[0]->vectorData( index, 1, &val[0] );
647 libply::ListProperty *lp = dynamic_cast<libply::ListProperty *>( &e[i + 3] );
648 lp->define( libply::Type::FLOAT64, 2 );
649 lp->value( 0 ) = val[0];
650 lp->value( 1 ) = val[1];
651 };
652 }
653 };
654
655
656 // write faces
657 std::vector<int> vertexIndices( mesh->faceVerticesMaximumCount() );
658 std::unique_ptr<MDAL::MeshFaceIterator> faces = mesh->readFaces();
659
660 libply::ElementWriteCallback faceCallback = [&faces, &fgroups, &vertexIndices, &volGroups]( libply::ElementBuffer & e, size_t index )
661 {
662 int idx = 0;
663 int faceOffsets[1];
664 faces->next( 1, faceOffsets, vertexIndices.size(), vertexIndices.data() );
665 libply::ListProperty *lp = dynamic_cast<libply::ListProperty *>( &e[idx] );
666 lp->define( libply::Type::UINT32, faceOffsets[0] );
667 for ( int j = 0; j < faceOffsets[0]; ++j )
668 {
669 lp->value( j ) = vertexIndices[j];
670 };
671 idx++;
672 for ( size_t i = 0; i < fgroups.size(); i++ )
673 {
674 if ( fgroups[i]->isScalar() )
675 {
676 double val[1];
677 fgroups[i]->datasets[0]->scalarData( index, 1, &val[0] );
678 e[idx] = val[0];
679 }
680 else
681 {
682 double val[2];
683 fgroups[i]->datasets[0]->vectorData( index, 1, &val[0] );
684 libply::ListProperty *lp = dynamic_cast<libply::ListProperty *>( &e[idx] );
685 lp->define( libply::Type::FLOAT64, 2 );
686 lp->value( 0 ) = val[0];
687 lp->value( 1 ) = val[1];
688 };
689 idx++;
690 }
691 int vCount[1];
692 int f2v[1];
693 for ( size_t i = 0; i < volGroups.size(); i++ )
694 {
695 std::shared_ptr<MDAL::MemoryDataset3D> ds = std::dynamic_pointer_cast<MDAL::MemoryDataset3D>( volGroups[i]->datasets[0] );
696 ds->verticalLevelCountData( index, 1, &vCount[0] );
697 const int count = vCount[0];
698 ds->faceToVolumeData( index, 1, &f2v[0] );
699 const int vindex = f2v[0];
700 std::vector<double> val( count, 0 );
701 ds->scalarVolumesData( vindex, count, val.data() );
702 libply::ListProperty *lp = dynamic_cast<libply::ListProperty *>( &e[idx] );
703 lp->define( libply::Type::FLOAT64, count );
704
705 for ( int j = 0; j < count; ++j )
706 {
707 lp->value( j ) = val[j];
708 };
709 idx++;
710 std::vector<double> ex( count + 1, 0 );
711 ds->verticalLevelData( vindex + index, count + 1, ex.data() );
712 libply::ListProperty *lp1 = dynamic_cast<libply::ListProperty *>( &e[idx] );
713 lp1->define( libply::Type::FLOAT64, count + 1 );
714 for ( int j = 0; j < count + 1; ++j )
715 {
716 lp1->value( j ) = ex[j];
717 };
718 idx++;
719 }
720 };
721
722 // write edges
723
724 std::unique_ptr<MDAL::MeshEdgeIterator> edges = mesh->readEdges();
725
726 libply::ElementWriteCallback edgeCallback = [&edges, &egroups]( libply::ElementBuffer & e, size_t index )
727 {
728 int startIndex;
729 int endIndex;
730 edges->next( 1, &startIndex, &endIndex );
731 e[0] = startIndex;
732 e[1] = endIndex;
733 for ( size_t i = 0; i < egroups.size(); i++ )
734 {
735 if ( egroups[i]->isScalar() )
736 {
737 double val[1];
738 egroups[i]->datasets[0]->scalarData( index, 1, &val[0] );
739 e[i + 2] = val[0];
740 }
741 else
742 {
743 double val[2];
744 egroups[i]->datasets[0]->vectorData( index, 1, &val[0] );
745 libply::ListProperty *lp = dynamic_cast<libply::ListProperty *>( &e[i + 2] );
746 lp->define( libply::Type::FLOAT64, 2 );
747 lp->value( 0 ) = val[0];
748 lp->value( 1 ) = val[1];
749 };
750 }
751 };
752
753 file.setElementWriteCallback( "vertex", vertexCallback );
754 if ( mesh->facesCount() > 0 ) file.setElementWriteCallback( "face", faceCallback );
755 if ( mesh->edgesCount() > 0 ) file.setElementWriteCallback( "edge", edgeCallback );
756
757 file.write();
758
759
760 /*
761 * Clean up
762 */
763 for ( size_t i = 0; i < vgroups.size(); ++i )
764 {
765 vgroups.pop_back();
766 };
767
768 for ( size_t i = 0; i < fgroups.size(); ++i )
769 {
770 fgroups.pop_back();
771 };
772
773 for ( size_t i = 0; i < egroups.size(); ++i )
774 {
775 egroups.pop_back();
776 };
777 }
778
persist(DatasetGroup * group)779 bool MDAL::DriverPly::persist( DatasetGroup *group )
780 {
781 save( group->uri(), "", group->mesh() );
782 return false;
783 }
784