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-------------------------------------------------------------------------------
11License
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
27Application
28 objToVTK
29
30Group
31 grpMeshManipulationUtilities
32
33Description
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
44using namespace Foam;
45
46// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
47
48string 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)
62labelList parseVertices(const string& line)
63{
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
114int main(int argc, char *argv[])
115{
116 argList::addNote
117 (
118 "Read obj line (not surface) file and convert into legacy VTK file"
119 );
120
121 argList::noParallel();
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// ************************************************************************* //
scalar y
Input/output from string buffers.
label n
label size_type
The type to represent the size of a buffer.
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition: DynamicList.H:72
DynamicList< T, SizeMin > & shrink()
Shrink the allocated space to the number of elements used.
Definition: DynamicListI.H:434
void append(const T &val)
Copy append an element to the end of this list.
Definition: DynamicListI.H:503
Input from string buffer, using a ISstream. Always UNCOMPRESSED.
Definition: StringStream.H:112
Output to file stream, using an OSstream.
Definition: OFstream.H:57
bool empty() const noexcept
True if the UList is empty (ie, size() is zero)
Definition: UListI.H:427
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
Extract command arguments and options from the supplied argc and argv parameters.
Definition: argList.H:124
T get(const label index) const
Get a value from the argument at index.
Definition: argListI.H:278
A class for handling file names.
Definition: fileName.H:76
A line primitive.
Definition: line.H:68
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
A class for handling words, derived from Foam::string.
Definition: word.H:68
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
const pointField & points
#define WarningInFunction
Report a warning using Foam::Warning.
Namespace for OpenFOAM.
messageStream Info
Information stream (stdout output on master, null elsewhere)
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:372
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
constexpr char nl
The newline '\n' character (0x0a)
Definition: Ostream.H:53
Foam::argList args(argc, argv)
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:333