fw4spl
core/fwDataIO/src/fwDataIO/reader/MeshReader.cpp
1 /* ***** BEGIN LICENSE BLOCK *****
2  * FW4SPL - Copyright (C) IRCAD, 2009-2017.
3  * Distributed under the terms of the GNU Lesser General Public License (LGPL) as
4  * published by the Free Software Foundation.
5  * ****** END LICENSE BLOCK ****** */
6 
7 #include "fwDataIO/reader/MeshReader.hpp"
8 
9 #include "fwDataIO/reader/registry/macros.hpp"
10 
11 #include <fwData/location/SingleFile.hpp>
12 #include <fwData/Mesh.hpp>
13 
14 #include <fwDataTools/helper/Array.hpp>
15 #include <fwDataTools/helper/Mesh.hpp>
16 
17 #include <boost/spirit/include/phoenix_bind.hpp>
18 #include <boost/spirit/include/phoenix_core.hpp>
19 #include <boost/spirit/include/phoenix_operator.hpp>
20 #include <boost/spirit/include/phoenix_statement.hpp>
21 #include <boost/spirit/include/phoenix_stl.hpp>
22 #include <boost/spirit/include/qi.hpp>
23 
24 #include <fstream>
25 #include <iostream>
26 
27 fwDataIOReaderRegisterMacro( ::fwDataIO::reader::MeshReader );
28 
29 namespace fwDataIO
30 {
31 
32 namespace reader
33 {
34 
35 //------------------------------------------------------------------------------
36 
38  ::fwData::Mesh::CellDataOffsetType current;
40  {
41  current = 0;
42  }
43  //------------------------------------------------------------------------------
44 
45  int operator()()
46  {
47  ::fwData::Mesh::CellDataOffsetType res = current;
48  current += 3;
49  return res;
50  }
51 };
52 
53 //------------------------------------------------------------------------------
54 
55 template <typename Iterator>
56 bool parseTrian2(Iterator first, Iterator last, ::fwData::Mesh::sptr mesh)
57 {
58  using boost::spirit::qi::ulong_long;
59  using boost::spirit::qi::int_;
60  using boost::spirit::qi::float_;
61  using boost::spirit::qi::phrase_parse;
62  using boost::spirit::qi::_1;
63  using boost::spirit::qi::_2;
64  using boost::spirit::qi::_3;
65  using boost::spirit::qi::_4;
66  using boost::spirit::qi::_5;
67  using boost::spirit::qi::_6;
68  using boost::spirit::qi::repeat;
69  using boost::spirit::ascii::space;
70  using boost::phoenix::push_back;
71  using boost::phoenix::ref;
72  namespace phx = boost::phoenix;
73 
74  unsigned long long int nbPoints;
75  unsigned long long int nbCells;
76 
77  mesh->allocateCellNormals();
78 
79  ::fwData::Array::sptr pointArray = mesh->getPointsArray();
80  ::fwData::Array::sptr cellDataArray = mesh->getCellDataArray();
81  ::fwData::Array::sptr cellTypesArray = mesh->getCellTypesArray();
82  ::fwData::Array::sptr cellDataOffsetsArray = mesh->getCellDataOffsetsArray();
83  ::fwData::Array::sptr cellNormalsArray = mesh->getCellNormalsArray();
84 
85  ::fwDataTools::helper::Array pointHelper(pointArray);
86  ::fwDataTools::helper::Array cellDataHelper(cellDataArray);
87  ::fwDataTools::helper::Array cellNormalsHelper(cellNormalsArray);
88  ::fwDataTools::helper::Array cellDataOffsetsHelper(cellDataOffsetsArray);
89  ::fwDataTools::helper::Array cellTypesHelper(cellTypesArray);
90 
91  ::fwData::Array::SizeType pointArraySize;
92  ::fwData::Array::SizeType cellArraySize;
93 
94  ::fwData::Mesh::PointValueType* pointArrayBuffer = 0;
95  ::fwData::Mesh::CellValueType* cellDataArrayBuffer = 0;
96  ::fwData::Mesh::NormalValueType* cellNormalsArrayBuffer = 0;
97 
98  // Starting from boost 1.65, the function could not be deduced
99  auto resizeFn =
100  phx::bind(static_cast<size_t(::fwData::Array::*)(const ::fwData::Array::SizeType&,
101  bool)>(&::fwData::Array::resize), pointArray,
102  std::ref(pointArraySize), true);
103 
104  bool r = phrase_parse(first, last,
105 
106  // Begin grammar
107  (
108  ulong_long
109  [
110  ref(nbPoints) = _1,
111  phx::bind(&::fwData::Mesh::setNumberOfPoints, mesh, _1),
112  phx::push_back(phx::ref(pointArraySize), phx::ref(nbPoints)),
113  resizeFn,
114  ref(pointArrayBuffer) =
115  phx::bind(&::fwDataTools::helper::Array::begin < ::fwData::Mesh::PointValueType >,
116  &pointHelper )
117  ]
118 
119  >> repeat(ref(nbPoints))
120  [
121  (float_ >> float_ >> float_)
122  [
123  *ref(pointArrayBuffer)++ = _1,
124  *ref(pointArrayBuffer)++ = _2,
125  *ref(pointArrayBuffer)++ = _3
126  ]
127  ]
128 
129  >> ulong_long
130  [
131  ref(nbCells) = _1,
132  phx::bind(&::fwData::Mesh::setNumberOfCells, mesh, _1),
133  phx::bind(&::fwData::Mesh::setCellDataSize, mesh, _1*3),
134  phx::bind(&::fwData::Mesh::adjustAllocatedMemory, mesh),
135  ref(cellDataArrayBuffer) =
136  phx::bind(&::fwDataTools::helper::Array::begin < ::fwData::Mesh::CellValueType >,
137  &cellDataHelper ),
138  ref(cellNormalsArrayBuffer) =
139  phx::bind(&::fwDataTools::helper::Array::begin < ::fwData::Mesh::NormalValueType >
140  ,
141  &cellNormalsHelper )
142  ]
143 
144  >> repeat(ref(nbCells))
145  [
146  (int_ >> int_ >> int_ >> float_ >> float_ >> float_)
147  [
148  *ref(cellDataArrayBuffer)++ = _1,
149  *ref(cellDataArrayBuffer)++ = _2,
150  *ref(cellDataArrayBuffer)++ = _3,
151  *ref(cellNormalsArrayBuffer)++ = _4,
152  *ref(cellNormalsArrayBuffer)++ = _5,
153  *ref(cellNormalsArrayBuffer)++ = _6
154  ]
155  ]
156  ),
157  // End grammar
158 
159  space
160  );
161 
162  std::fill(
163  cellTypesHelper.begin< ::fwData::Mesh::CellTypes >(),
164  cellTypesHelper.end< ::fwData::Mesh::CellTypes >(),
165  static_cast< ::fwData::Mesh::CellTypes >(::fwData::Mesh::TRIANGLE)
166  );
167 
168  cell_data_offset_generator cellDataOffsetGenerator;
169 
170  std::generate(
171  cellDataOffsetsHelper.begin< ::fwData::Mesh::CellDataOffsetType >(),
172  cellDataOffsetsHelper.end< ::fwData::Mesh::CellDataOffsetType >(),
173  cellDataOffsetGenerator
174  );
175 
176  // Check if normals array is filled of -1. values
177  const float normalBadValue = -1.f;
178  float normal = normalBadValue;
179  int& n = *reinterpret_cast<int*>(&normal);
180 
181  std::for_each(
182  cellNormalsHelper.begin< int >(),
183  cellNormalsHelper.end< int >(),
184  ref(n) &= boost::phoenix::arg_names::arg1
185  );
186 
187  if (normal == -1)
188  {
189  mesh->clearCellNormals();
190  SLM_WARN("normals equals to (-1,-1,-1) : normals removed.");
191  }
192 
193  if (first != last) // fail if we didn't get a full match
194  {
195  return false;
196  }
197  return r;
198 
199 }
200 
201 //------------------------------------------------------------------------------
202 
204  ::fwData::location::enableSingleFile< IObjectReader >(this)
205 {
206 }
207 
208 //------------------------------------------------------------------------------
209 
211 {
212 }
213 
214 //------------------------------------------------------------------------------
215 
217 {
218  assert( std::dynamic_pointer_cast< ::fwData::location::SingleFile >(m_location) );
219  ::boost::filesystem::path path = std::dynamic_pointer_cast< ::fwData::location::SingleFile >(m_location)->getPath();
220 
221  SLM_TRACE( "Trian file: " + path.string());
222  SLM_ASSERT("Empty path for Trian file", !path.empty() );
223 
224  size_t length;
225  //char *buffer;
226  std::string buf;
227  std::ifstream file;
228  file.open(path.string().c_str(), std::ios::binary );
229 
230  if (!file.is_open())
231  {
232  SLM_ERROR( "Trian file loading error for " + path.string());
233  throw std::ios_base::failure("Unable to open " + path.string());
234  }
235 
236  file.seekg(0, std::ios::end);
237  length = file.tellg();
238  file.seekg(0, std::ios::beg);
239 
240  //buffer = new char [length];
241  buf.resize(length);
242  char* buffer = &buf[0];
243 
244  file.read(buffer, length);
245  file.close();
246 
247  ::fwData::Mesh::sptr mesh = getConcreteObject();
248 
249  mesh->clear();
250 
251  if (!parseTrian2(buffer, buffer+length, mesh))
252  {
253  OSLM_ERROR( "Bad file format : " << path.string());
254  throw std::ios_base::failure("Unable to open " + path.string() + " : Bad file format.");
255  }
256 
257 }
258 
259 //------------------------------------------------------------------------------
260 
261 std::string MeshReader::extension()
262 {
263  return (".trian");
264 }
265 
266 //------------------------------------------------------------------------------
267 
268 } // namespace reader
269 } // namespace fwDataIO
virtual FWDATA_API size_t resize(const ::fwTools::Type &type, const SizeType &size, size_t nbOfComponents, bool reallocate=false)
Resizes and allocate (if needed) the array.
std::vector< size_t > SizeType
Array size type.
This class defines a single file location.
Definition: SingleFile.hpp:25
FWDATA_API bool adjustAllocatedMemory()
Adjust mesh memory usage.
This namespace fwDataIO contains reader and writer for several framework&#39;s data.
Key class used to restrict access to Object construction. See http://www.drdobbs.com/184402053.
#define SLM_WARN(message)
Definition: spyLog.hpp:261
#define SLM_ERROR(message)
Definition: spyLog.hpp:272
Provides a way to manage a view on a multidimentionnal array.
#define OSLM_ERROR(message)
Definition: spyLog.hpp:274
virtual FWDATATOOLS_API char * begin()
Returns the begining/end of the buffer interpreted as a char buffer.
FWDATAIO_API MeshReader(::fwDataIO::reader::IObjectReader::Key key)
Constructor. Do nothing.
#define SLM_ASSERT(message, cond)
work like &#39;assert&#39; from &#39;cassert&#39;, with in addition a message logged by spylog (with FATAL loglevel) ...
Definition: spyLog.hpp:308
virtual std::shared_ptr< DataType > getConcreteObject()
m_object getter.
virtual FWDATAIO_API void read() override
Read the file with standard iostream API.
FWDATA_API void setNumberOfPoints(Id nb)
Set number of points.
#define SLM_TRACE(message)
Definition: spyLog.hpp:228
FWDATA_API void setCellDataSize(Id nb)
Set cell data size.
Contains the representation of the data objects used in the framework.
FWDATA_API void setNumberOfCells(Id nb)
Set number of cells.
virtual FWDATAIO_API ~MeshReader()
Destructor. Do nothing.
::fwData::location::ILocation::sptr m_location
Object location ( file path, directory path, url, etc )
Helper to manage array buffer. Lock the buffer before to modify it.