surfaceTransformPoints.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-2016 OpenFOAM Foundation
9 Copyright (C) 2017-2022 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 surfaceTransformPoints
29
30Group
31 grpSurfaceUtilities
32
33Description
34 Transform (scale/rotate) a surface.
35 Like transformPoints but for surfaces.
36
37 The rollPitchYaw and yawPitchRoll options take three angles (degrees)
38 that describe the intrinsic Euler rotation.
39
40 rollPitchYaw
41 - roll (rotation about X) followed by
42 - pitch (rotation about Y) followed by
43 - yaw (rotation about Z)
44
45 yawPitchRoll
46 - yaw (rotation about Z) followed by
47 - pitch (rotation about Y) followed by
48 - roll (rotation about X)
49
50\*---------------------------------------------------------------------------*/
51
52#include "argList.H"
53#include "Fstream.H"
54#include "boundBox.H"
55#include "transformField.H"
56#include "Pair.H"
57#include "Tuple2.H"
58#include "axisAngleRotation.H"
60#include "MeshedSurfaces.H"
61
62using namespace Foam;
63using namespace Foam::coordinateRotations;
64
65static word getExtension(const fileName& name)
66{
67 word ext(name.ext());
68 if (ext == "gz")
69 {
70 ext = name.lessExt().ext();
71 }
72
73 return ext;
74}
75
76
77// Non-short-circuiting check to get all warnings
78static bool hasReadWriteTypes(const word& readType, const word& writeType)
79{
80 volatile bool good = true;
81
82 if (!meshedSurface::canReadType(readType, true))
83 {
84 good = false;
85 }
86
87 if (!meshedSurface::canWriteType(writeType, true))
88 {
89 good = false;
90 }
91
92 return good;
93}
94
95
96// Retrieve scaling option
97// - size 0 : no scaling
98// - size 1 : uniform scaling
99// - size 3 : non-uniform scaling
100List<scalar> getScalingOpt(const word& optName, const argList& args)
101{
102 // readListIfPresent handles single or multiple values
103 // - accept 1 or 3 values
104
105 List<scalar> scaling;
106 args.readListIfPresent(optName, scaling);
107
108 if (scaling.size() == 1)
109 {
110 // Uniform scaling
111 }
112 else if (scaling.size() == 3)
113 {
114 // Non-uniform, but may actually be uniform
115 if
116 (
117 equal(scaling[0], scaling[1])
118 && equal(scaling[0], scaling[2])
119 )
120 {
121 scaling.resize(1);
122 }
123 }
124 else if (!scaling.empty())
125 {
127 << "Incorrect number of components, must be 1 or 3." << nl
128 << " -" << optName << ' ' << args[optName].c_str() << endl
129 << exit(FatalError);
130 }
131
132 if (scaling.size() == 1 && equal(scaling[0], 1))
133 {
134 // Scale factor 1 == no scaling
135 scaling.clear();
136 }
137
138 // Zero and negative scaling are permitted
139
140 return scaling;
141}
142
143
144void applyScaling(pointField& points, const List<scalar>& scaling)
145{
146 if (scaling.size() == 1)
147 {
148 Info<< "Scaling points uniformly by " << scaling[0] << nl;
149 points *= scaling[0];
150 }
151 else if (scaling.size() == 3)
152 {
153 Info<< "Scaling points by ("
154 << scaling[0] << ' '
155 << scaling[1] << ' '
156 << scaling[2] << ')' << nl;
157
158 points.replace(vector::X, scaling[0]*points.component(vector::X));
159 points.replace(vector::Y, scaling[1]*points.component(vector::Y));
160 points.replace(vector::Z, scaling[2]*points.component(vector::Z));
161 }
162}
163
164
165// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
166
167int main(int argc, char *argv[])
168{
169 argList::addNote
170 (
171 "Transform (translate / rotate / scale) surface points.\n"
172 "Like transformPoints but for surfaces.\n"
173 "Note: roll=rotate about x, pitch=rotate about y, yaw=rotate about z"
174 );
175 argList::noParallel();
176 argList::addArgument("input", "The input surface file");
177 argList::addArgument("output", "The output surface file");
178 argList::addBoolOption
179 (
180 "recentre",
181 "Recentre the bounding box before other operations"
182 );
183 argList::addOption
184 (
185 "translate",
186 "vector",
187 "Translate by specified <vector> before rotations"
188 );
189 argList::addBoolOption
190 (
191 "auto-origin",
192 "Use bounding box centre as origin for rotations"
193 );
194 argList::addOption
195 (
196 "origin",
197 "point",
198 "Use specified <point> as origin for rotations"
199 );
200 argList::addOption
201 (
202 "rotate",
203 "(vectorA vectorB)",
204 "Rotate from <vectorA> to <vectorB> - eg, '((1 0 0) (0 0 1))'"
205 );
206 argList::addOption
207 (
208 "rotate-angle",
209 "(vector angle)",
210 "Rotate <angle> degrees about <vector> - eg, '((1 0 0) 45)'"
211 );
212 argList::addOption
213 (
214 "rotate-x", "deg",
215 "Rotate (degrees) about x-axis"
216 );
217 argList::addOption
218 (
219 "rotate-y", "deg",
220 "Rotate (degrees) about y-axis"
221 );
222 argList::addOption
223 (
224 "rotate-z", "deg",
225 "Rotate (degrees) about z-axis"
226 );
227 argList::addOption
228 (
229 "rollPitchYaw",
230 "vector",
231 "Rotate by '(roll pitch yaw)' degrees"
232 );
233 argList::addOption
234 (
235 "yawPitchRoll",
236 "vector",
237 "Rotate by '(yaw pitch roll)' degrees"
238 );
239 argList::addOption
240 (
241 "read-scale",
242 "scalar | vector",
243 "Uniform or non-uniform input scaling"
244 );
245 argList::addOption
246 (
247 "write-scale",
248 "scalar | vector",
249 "Uniform or non-uniform output scaling"
250 );
251 argList::addOption
252 (
253 "read-format",
254 "type",
255 "Input format (default: use file extension)"
256 );
257 argList::addOption
258 (
259 "write-format",
260 "type",
261 "Output format (default: use file extension)"
262 );
263
264 // Backward compatibility and with transformPoints
265 argList::addOptionCompat("write-scale", {"scale", -2006});
266
267 argList args(argc, argv);
268
269 // Verify that an operation has been specified
270 {
271 const List<word> operationNames
272 ({
273 "recentre",
274 "translate",
275 "rotate",
276 "rotate-angle",
277 "rotate-x",
278 "rotate-y",
279 "rotate-z",
280 "rollPitchYaw",
281 "yawPitchRoll",
282 "read-scale",
283 "write-scale"
284 });
285
286 if (!args.count(operationNames))
287 {
289 << "No operation supplied, "
290 << "use at least one of the following:" << nl
291 << " ";
292
293 for (const auto& opName : operationNames)
294 {
296 << " -" << opName;
297 }
298
300 << nl << exit(FatalError);
301 }
302 }
303
304 const auto importName = args.get<fileName>(1);
305 const auto exportName = args.get<fileName>(2);
306
307 const word readFileType
308 (
309 args.getOrDefault<word>("read-format", getExtension(importName))
310 );
311
312 const word writeFileType
313 (
314 args.getOrDefault<word>("write-format", getExtension(exportName))
315 );
316
317
318 // Check that reading/writing is supported
319 if (!hasReadWriteTypes(readFileType, writeFileType))
320 {
322 << "Unsupported file format(s)" << nl
323 << exit(FatalError);
324 }
325
326
327 Info<< "Reading surf from " << importName << " ..." << nl
328 << "Writing surf to " << exportName << " ..." << endl;
329
330
331 meshedSurface surf1(importName, readFileType);
332
333 pointField points(surf1.points());
334
335
336 // Begin operations
337
338 // Input scaling
339 applyScaling(points, getScalingOpt("read-scale", args));
340
341 vector v;
342 if (args.found("recentre"))
343 {
344 v = boundBox(points).centre();
345 Info<< "Adjust centre " << v << " -> (0 0 0)" << endl;
346 points -= v;
347 }
348
349 if (args.readIfPresent("translate", v))
350 {
351 Info<< "Translating points by " << v << endl;
352 points += v;
353 }
354
355 vector origin;
356 bool useOrigin = args.readIfPresent("origin", origin);
357 if (args.found("auto-origin") && !useOrigin)
358 {
359 useOrigin = true;
360 origin = boundBox(points).centre();
361 }
362
363 if (useOrigin)
364 {
365 Info<< "Set origin for rotations to " << origin << endl;
366 points -= origin;
367 }
368
369
370 // Get a rotation specification
371
372 tensor rot(Zero);
373 bool useRotation(false);
374
375 if (args.found("rotate"))
376 {
377 Pair<vector> n1n2
378 (
379 args.lookup("rotate")()
380 );
381 n1n2[0].normalise();
382 n1n2[1].normalise();
383
384 rot = rotationTensor(n1n2[0], n1n2[1]);
385 useRotation = true;
386 }
387 else if (args.found("rotate-angle"))
388 {
389 const Tuple2<vector, scalar> rotAxisAngle
390 (
391 args.lookup("rotate-angle")()
392 );
393
394 const vector& axis = rotAxisAngle.first();
395 const scalar angle = rotAxisAngle.second();
396
397 Info<< "Rotating points " << nl
398 << " about " << axis << nl
399 << " angle " << angle << nl;
400
401 rot = axisAngle::rotation(axis, angle, true);
402 useRotation = true;
403 }
404 else if (args.found("rotate-x"))
405 {
406 const scalar angle = args.get<scalar>("rotate-x");
407
408 Info<< "Rotating points about x-axis: " << angle << nl;
409
410 rot = axisAngle::rotation(vector::X, angle, true);
411 useRotation = true;
412 }
413 else if (args.found("rotate-y"))
414 {
415 const scalar angle = args.get<scalar>("rotate-y");
416
417 Info<< "Rotating points about y-axis: " << angle << nl;
418
419 rot = axisAngle::rotation(vector::Y, angle, true);
420 useRotation = true;
421 }
422 else if (args.found("rotate-z"))
423 {
424 const scalar angle = args.get<scalar>("rotate-z");
425
426 Info<< "Rotating points about z-axis: " << angle << nl;
427
428 rot = axisAngle::rotation(vector::Z, angle, true);
429 useRotation = true;
430 }
431 else if (args.readIfPresent("rollPitchYaw", v))
432 {
433 Info<< "Rotating points by" << nl
434 << " roll " << v.x() << nl
435 << " pitch " << v.y() << nl
436 << " yaw " << v.z() << nl;
437
438 rot = euler::rotation(euler::eulerOrder::ROLL_PITCH_YAW, v, true);
439 useRotation = true;
440 }
441 else if (args.readIfPresent("yawPitchRoll", v))
442 {
443 Info<< "Rotating points by" << nl
444 << " yaw " << v.x() << nl
445 << " pitch " << v.y() << nl
446 << " roll " << v.z() << nl;
447
448 rot = euler::rotation(euler::eulerOrder::YAW_PITCH_ROLL, v, true);
449 useRotation = true;
450 }
451
452 if (useRotation)
453 {
454 Info<< "Rotating points by " << rot << endl;
455 transform(points, rot, points);
456 }
457
458 // Output scaling
459 applyScaling(points, getScalingOpt("write-scale", args));
460
461 if (useOrigin)
462 {
463 Info<< "Unset origin for rotations from " << origin << endl;
464 points += origin;
465 }
466
467 surf1.movePoints(points);
468 surf1.write(exportName, writeFileType);
469
470 Info<< "End\n" << endl;
471
472 return 0;
473}
474
475
476// ************************************************************************* //
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: List.H:77
void resize(const label len)
Adjust allocated size of list.
Definition: ListI.H:139
void clear()
Clear the list, i.e. set size to zero.
Definition: ListI.H:116
An ordered pair of two objects of type <T> with first() and second() elements.
Definition: Pair.H:69
A 2-tuple for storing two objects of dissimilar types. The container is similar in purpose to std::pa...
Definition: Tuple2.H:58
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
bool readListIfPresent(const word &optName, List< T > &list) const
Definition: argListI.H:394
label count(const UList< word > &optionNames) const
Return how many of the specified options were used.
Definition: argList.C:1760
bool found(const word &optName) const
Return true if the named option is found.
Definition: argListI.H:178
bool readIfPresent(const word &optName, T &val) const
Read a value from the named option if present.
Definition: argListI.H:323
ITstream lookup(const word &optName) const
Return an input stream from the named option.
Definition: argListI.H:184
T getOrDefault(const word &optName, const T &deflt) const
Get a value from the named option if present, or return default.
Definition: argListI.H:307
A bounding box defined in terms of min/max extrema points.
Definition: boundBox.H:64
point centre() const
The centre (midpoint) of the bounding box.
Definition: boundBoxI.H:115
A class for handling file names.
Definition: fileName.H:76
Tensor of scalars, i.e. Tensor<scalar>.
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
word ext() const
Return file name extension (part after last .)
Definition: word.C:126
word lessExt() const
Return word without extension (part before last .)
Definition: word.C:113
const pointField & points
bool equal(const Matrix< Form1, Type > &A, const Matrix< Form2, Type > &B, const bool verbose=false, const label maxDiffs=10, const scalar relTol=1e-5, const scalar absTol=1e-8)
Compare matrix elements for absolute or relative equality.
Definition: MatrixTools.C:34
Namespace for coordinate system rotations.
Definition: axesRotation.C:38
Namespace for OpenFOAM.
dimensionSet transform(const dimensionSet &ds)
Return the argument; transformations do not change the dimensions.
Definition: dimensionSet.C:536
tensor rotationTensor(const vector &n1, const vector &n2)
Rotational transformation tensor from vector n1 to n2.
Definition: transform.H:51
messageStream Info
Information stream (stdout output on master, null elsewhere)
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:372
error FatalError
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for INVALID.
Definition: exprTraits.C:59
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)
Spatial transformation functions for primitive fields.