objToVTK.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2011-2015 OpenFOAM Foundation
9  Copyright (C) 2019-2021 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 Application
28  objToVTK
29 
30 Group
31  grpMeshManipulationUtilities
32 
33 Description
34  Read obj line (not surface) file and convert into legacy VTK file.
35 
36 \*---------------------------------------------------------------------------*/
37 
38 #include "argList.H"
39 #include "OFstream.H"
40 #include "StringStream.H"
41 #include "point.H"
42 #include "DynamicList.H"
43 
44 using namespace Foam;
45 
46 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
47 
48 string getLine(std::ifstream& is)
49 {
50  string line;
51  do
52  {
53  std::getline(is, line);
54  }
55  while (line.starts_with('#'));
56 
57  return line;
58 }
59 
60 
61 // Read space-separated vertices (with optional '/' arguments)
62 labelList parseVertices(const string& line)
63 {
64  DynamicList<label> verts;
65 
66  // Assume 'l' is followed by space.
67  string::size_type endNum = 1;
68 
69  do
70  {
71  string::size_type startNum = line.find_first_not_of(' ', endNum);
72 
73  if (startNum == string::npos)
74  {
75  break;
76  }
77 
78  endNum = line.find(' ', startNum);
79 
80  string vertexSpec;
81  if (endNum != string::npos)
82  {
83  vertexSpec = line.substr(startNum, endNum-startNum);
84  }
85  else
86  {
87  vertexSpec = line.substr(startNum, line.size() - startNum);
88  }
89 
90  string::size_type slashPos = vertexSpec.find('/');
91 
92  label vertI = 0;
93  if (slashPos != string::npos)
94  {
95  IStringStream intStream(vertexSpec.substr(0, slashPos));
96 
97  intStream >> vertI;
98  }
99  else
100  {
101  IStringStream intStream(vertexSpec);
102 
103  intStream >> vertI;
104  }
105  verts.append(vertI - 1);
106  }
107  while (true);
108 
109  return verts.shrink();
110 }
111 
112 
113 
114 int main(int argc, char *argv[])
115 {
117  (
118  "Read obj line (not surface) file and convert into legacy VTK file"
119  );
120 
122  argList::addArgument("obj-file", "The input obj line file");
123  argList::addArgument("vtk-file", "The output vtk file");
124  argList args(argc, argv);
125 
126  const auto objName = args.get<fileName>(1);
127  const auto outName = args.get<fileName>(2);
128 
129  std::ifstream OBJfile(objName);
130 
131  Info<< "Processing file " << objName << endl;
132 
133  if (!OBJfile.good())
134  {
136  << "Cannot read file " << objName << exit(FatalError);
137  }
138 
139  // Points and lines
141  DynamicList<vector> pointNormals;
142  DynamicList<labelList> polyLines;
143  DynamicList<labelList> polygons;
144 
145  bool hasWarned = false;
146 
147  label lineNo = 0;
148  while (OBJfile.good())
149  {
150  const string line = getLine(OBJfile);
151  lineNo++;
152 
153  if (line.empty()) continue;
154 
155  // Read first word
156  IStringStream lineStream(line);
157  word cmd(lineStream);
158 
159  if (cmd == "v")
160  {
161  scalar x, y, z;
162 
163  lineStream >> x >> y >> z;
164 
165  points.append(point(x, y, z));
166  }
167  else if (cmd == "vn")
168  {
169  scalar x, y, z;
170 
171  lineStream >> x >> y >> z;
172 
173  pointNormals.append(vector(x, y, z));
174  }
175  else if (cmd == "l")
176  {
177  polyLines.append(parseVertices(line));
178  }
179  else if (cmd == "f")
180  {
181  polygons.append(parseVertices(line));
182  }
183  else if (cmd != "")
184  {
185  if (!hasWarned)
186  {
187  hasWarned = true;
188 
190  << "Unrecognized OBJ command " << cmd << nl
191  << "In line " << lineStream.str()
192  << " at linenumber " << lineNo << nl
193  << "Only recognized commands are 'v' and 'l'.\n"
194  << "If this is a surface command use surfaceConvert instead"
195  << " to convert to a file format that can be read by VTK"
196  << endl;
197  }
198  }
199  }
200 
201 
202  //
203  // Write as vtk 'polydata' file
204  //
205 
206 
207  OFstream outFile(outName);
208 
209  outFile
210  << "# vtk DataFile Version 2.0\n"
211  << objName << nl
212  << "ASCII\n"
213  << "DATASET POLYDATA\n"
214  << "POINTS " << points.size() << " double\n";
215 
216  for (const point& pt : points)
217  {
218  outFile
219  << float(pt.x()) << ' '
220  << float(pt.y()) << ' '
221  << float(pt.z()) << nl;
222  }
223 
224  outFile
225  << "VERTICES " << points.size() << ' ' << (2 * points.size()) << nl;
226 
227  forAll(points, i)
228  {
229  outFile << 1 << ' ' << i << nl;
230  }
231 
232  label nItems = 0;
233  forAll(polyLines, polyI)
234  {
235  nItems += polyLines[polyI].size() + 1;
236  }
237 
238  outFile
239  << "LINES " << polyLines.size() << ' ' << nItems << nl;
240 
241  forAll(polyLines, polyI)
242  {
243  const labelList& line = polyLines[polyI];
244 
245  outFile << line.size();
246 
247  forAll(line, i)
248  {
249  outFile << ' ' << line[i];
250  }
251  outFile << nl;
252  }
253 
254 
255  nItems = 0;
256  forAll(polygons, polyI)
257  {
258  nItems += polygons[polyI].size() + 1;
259  }
260 
261  outFile
262  << "POLYGONS " << polygons.size() << ' ' << nItems << nl;
263 
264  forAll(polygons, polyI)
265  {
266  const labelList& line = polygons[polyI];
267 
268  outFile << line.size();
269 
270  forAll(line, i)
271  {
272  outFile << ' ' << line[i];
273  }
274  outFile << nl;
275  }
276 
277 
278  outFile
279  << "POINT_DATA " << points.size() << nl
280  << "SCALARS pointID double 1\n"
281  << "LOOKUP_TABLE default\n";
282 
283  forAll(points, i)
284  {
285  outFile << i;
286 
287  if ((i % 10) == 1)
288  {
289  outFile << nl;
290  }
291  else
292  {
293  outFile << ' ';
294  }
295  }
296 
297  if (!pointNormals.empty())
298  {
299  outFile << nl << "NORMALS pointNormals double\n";
300 
301  for(const vector& n : pointNormals)
302  {
303  outFile
304  << float(n.x()) << ' '
305  << float(n.y()) << ' '
306  << float(n.z()) << nl;
307  }
308  }
309 
310  Info<< "End\n" << endl;
311 
312  return 0;
313 }
314 
315 
316 // ************************************************************************* //
static void addNote(const string &note)
Add extra notes for the usage information.
Definition: argList.C:462
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
A line primitive.
Definition: line.H:52
A class for handling file names.
Definition: fileName.H:72
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:608
Input/output from string buffers.
void append(const T &val)
Append an element at the end of the list.
Definition: List.H:521
Output to file stream as an OSstream, normally using std::ofstream for the actual output...
Definition: OFstream.H:71
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
bool empty() const noexcept
True if List is empty (ie, size() is zero)
Definition: UList.H:675
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
static void noParallel()
Remove the parallel options.
Definition: argList.C:584
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
scalar y
const pointField & points
A class for handling words, derived from Foam::string.
Definition: word.H:63
Extract command arguments and options from the supplied argc and argv parameters. ...
Definition: argList.H:118
Vector< scalar > vector
Definition: vector.H:57
void append(const T &val)
Copy append an element to the end of this list.
Definition: DynamicList.H:584
graph_traits< Graph >::vertices_size_type size_type
Definition: SloanRenumber.C:67
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
DynamicList< T, SizeMin > & shrink()
Calls shrink_to_fit() and returns a reference to the DynamicList.
Definition: DynamicListI.H:447
vector point
Point is a vector.
Definition: point.H:37
T get(const label index) const
Get a value from the argument at index.
Definition: argListI.H:271
#define WarningInFunction
Report a warning using Foam::Warning.
Input from string buffer, using a ISstream. Always UNCOMPRESSED.
Definition: StringStream.H:52
static void addArgument(const string &argName, const string &usage="")
Append a (mandatory) argument to validArgs.
Definition: argList.C:351
messageStream Info
Information stream (stdout output on master, null elsewhere)
label n
Foam::argList args(argc, argv)
Namespace for OpenFOAM.