Loading...
Searching...
No Matches
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-2025 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 "stringOps.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// Token list with one of the following:
62// f v1 v2 v3 ...
63// f v1/vt1 v2/vt2 v3/vt3 ...
64// l v1 v2 v3 ...
65// l v1/vt1 v2/vt2 v3/vt3 ...
66static label readObjVertices
67(
68 const SubStrings& tokens,
70)
71{
72 verts.clear();
73
74 bool first = true;
75 for (const auto& tok : tokens)
76 {
77 if (first)
78 {
79 // skip initial "f" or "l"
80 first = false;
81 continue;
82 }
83
84 std::string vrtSpec(tok.str());
85
86 if
87 (
88 const auto slash = vrtSpec.find('/');
89 slash != std::string::npos
90 )
91 {
92 vrtSpec.erase(slash);
93 }
94
95 label vertId = readLabel(vrtSpec);
96
97 verts.push_back(vertId - 1);
98 }
99
100 return verts.size();
101}
102
103// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
104
105int main(int argc, char *argv[])
106{
108 (
109 "Read obj line (not surface) file and convert into legacy VTK file"
110 );
111
113 argList::addArgument("obj-file", "The input obj line file");
114 argList::addArgument("vtk-file", "The output vtk file");
115 argList args(argc, argv);
116
117 const auto objName = args.get<fileName>(1);
118 const auto outName = args.get<fileName>(2);
119
120 std::ifstream OBJfile(objName);
121
122 Info<< "Processing file " << objName << endl;
123
124 if (!OBJfile.good())
125 {
127 << "Cannot read file " << objName << exit(FatalError);
128 }
129
130 // Points and lines
132 DynamicList<vector> pointNormals;
133 DynamicList<labelList> polyLines;
134 DynamicList<labelList> polygons;
135
136 DynamicList<label> dynVerts;
137
138 bool hasWarned = false;
139
140 label lineNo = 0;
141 while (OBJfile.good())
142 {
143 const string line = getLine(OBJfile);
144 lineNo++;
145
146 if (line.empty()) continue;
147
148 const auto tokens = stringOps::splitSpace(line);
149
150 // Require command and some arguments
151 if (tokens.size() < 2)
152 {
153 continue;
154 }
155
156 const word cmd = word::validate(tokens[0]);
157
158 if (cmd == "v")
159 {
160 // Vertex
161 // v x y z
162
163 points.emplace_back
164 (
165 readScalar(tokens[1]),
166 readScalar(tokens[2]),
167 readScalar(tokens[3])
168 );
169 }
170 else if (cmd == "vn")
171 {
172 // Vertex normals
173 // vn x y z
174
175 pointNormals.emplace_back
176 (
177 readScalar(tokens[1]),
178 readScalar(tokens[2]),
179 readScalar(tokens[3])
180 );
181 }
182 else if (cmd == "l")
183 {
184 // Line
185 // l v1 v2 v3 ...
186 // OR
187 // l v1/vt1 v2/vt2 v3/vt3 ...
188
189 readObjVertices(tokens, dynVerts);
190 polyLines.emplace_back() = dynVerts;
191 }
192 else if (cmd == "f")
193 {
194 // f v1 v2 v3 ...
195 // OR
196 // f v1/vt1 v2/vt2 v3/vt3 ...
197
198 readObjVertices(tokens, dynVerts);
199 polygons.emplace_back() = dynVerts;
200 }
201 else if (cmd != "")
202 {
203 if (!hasWarned)
204 {
205 hasWarned = true;
206
208 << "Unrecognized OBJ command " << cmd << nl
209 << "In line " << line
210 << " at linenumber " << lineNo << nl
211 << "Only recognized commands are 'v' and 'l'.\n"
212 << "If this is a surface command use surfaceConvert instead"
213 << " to convert to a file format that can be read by VTK"
214 << endl;
215 }
216 }
217 }
218
219
220 //
221 // Write as vtk 'polydata' file
222 //
223
224
225 OFstream outFile(outName);
226
227 outFile
228 << "# vtk DataFile Version 2.0\n"
229 << objName << nl
230 << "ASCII\n"
231 << "DATASET POLYDATA\n"
232 << "POINTS " << points.size() << " double\n";
233
234 for (const point& pt : points)
235 {
236 outFile
237 << float(pt.x()) << ' '
238 << float(pt.y()) << ' '
239 << float(pt.z()) << nl;
240 }
241
242 outFile
243 << "VERTICES " << points.size() << ' ' << (2 * points.size()) << nl;
244
245 forAll(points, i)
246 {
247 outFile << 1 << ' ' << i << nl;
248 }
249
250 label nItems = 0;
251 for (const labelList& line : polyLines)
252 {
253 nItems += line.size() + 1;
254 }
255
256 outFile
257 << "LINES " << polyLines.size() << ' ' << nItems << nl;
258
259 for (const labelList& line : polyLines)
260 {
261 outFile << line.size();
262
263 for (const label vrt : line)
264 {
265 outFile << ' ' << vrt;
266 }
267 outFile << nl;
268 }
269
270
271 nItems = 0;
272 for (const labelList& line : polygons)
273 {
274 nItems += line.size() + 1;
275 }
276
277 outFile
278 << "POLYGONS " << polygons.size() << ' ' << nItems << nl;
279
280 for (const labelList& line : polygons)
281 {
282 outFile << line.size();
283
284 for (const label vrt : line)
285 {
286 outFile << ' ' << vrt;
287 }
288 outFile << nl;
289 }
290
291
292 outFile
293 << "POINT_DATA " << points.size() << nl
294 << "SCALARS pointID double 1\n"
295 << "LOOKUP_TABLE default\n";
296
297 forAll(points, i)
298 {
299 outFile << i;
300
301 if ((i % 10) == 1)
302 {
303 outFile << nl;
304 }
305 else
306 {
307 outFile << ' ';
308 }
309 }
310
311 if (!pointNormals.empty())
312 {
313 outFile << nl << "NORMALS pointNormals double\n";
314
315 for(const vector& n : pointNormals)
316 {
317 outFile
318 << float(n.x()) << ' '
319 << float(n.y()) << ' '
320 << float(n.z()) << nl;
321 }
322 }
323
324 Info<< "End\n" << endl;
325
326 return 0;
327}
328
329
330// ************************************************************************* //
label n
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition DynamicList.H:68
void clear() noexcept
Clear the addressed list, i.e. set the size to zero.
T & emplace_back(Args &&... args)
Construct an element at the end of the list, return reference to the new list element.
void push_back(const T &val)
Copy append an element to the end of this list.
Output to file stream as an OSstream, normally using std::ofstream for the actual output.
Definition OFstream.H:75
Sub-ranges of a string with a structure similar to std::match_results, but without the underlying reg...
Definition SubStrings.H:49
bool empty() const noexcept
True if List is empty (ie, size() is zero).
Definition UList.H:701
void size(const label n)
Older name for setAddressableSize.
Definition UList.H:118
Extract command arguments and options from the supplied argc and argv parameters.
Definition argList.H:119
static void addArgument(const string &argName, const string &usage="")
Append a (mandatory) argument to validArgs.
Definition argList.C:366
static void noParallel()
Remove the parallel options.
Definition argList.C:599
static void addNote(const string &note)
Add extra notes for the usage information.
Definition argList.C:477
A class for handling file names.
Definition fileName.H:75
A line primitive.
Definition line.H:180
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:66
static word validate(const std::string &s, const bool prefix=false)
Construct validated word (no invalid characters).
Definition word.C:39
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition error.H:600
const pointField & points
#define WarningInFunction
Report a warning using Foam::Warning.
Foam::SubStrings splitSpace(const std::string &str, std::string::size_type pos=0)
Split string into sub-strings at whitespace (TAB, NL, VT, FF, CR, SPC).
Namespace for OpenFOAM.
List< label > labelList
A List of labels.
Definition List.H:62
label readLabel(const char *buf)
Parse entire buffer as a label, skipping leading/trailing whitespace.
Definition label.H:63
messageStream Info
Information stream (stdout output on master, null elsewhere).
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition Ostream.H:519
vector point
Point is a vector.
Definition point.H:37
error FatalError
Error stream (stdout output on all processes), with additional 'FOAM FATAL ERROR' header text and sta...
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition errorManip.H:125
constexpr char nl
The newline '\n' character (0x0a).
Definition Ostream.H:50
static label readObjVertices(const SubStrings &tokens, DynamicList< label > &verts)
Foam::argList args(argc, argv)
#define forAll(list, i)
Loop across all elements in list.
Definition stdFoam.H:299