Loading...
Searching...
No Matches
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,2024 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#include "cylindricalCS.H"
62
63using namespace Foam;
64using namespace Foam::coordinateRotations;
65
66static word getExtension(const fileName& name)
67{
68 return
69 (
70 name.has_ext("gz")
71 ? name.stem().ext()
72 : name.ext()
73 );
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 const vector factor(scaling[0], scaling[1], scaling[2]);
154 Info<< "Scaling points by " << factor << nl;
155 cmptMultiply(points, points, factor);
156 }
157}
158
159
160// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
161
162int main(int argc, char *argv[])
163{
165 (
166 "Transform (translate / rotate / scale) surface points.\n"
167 "Like transformPoints but for surfaces.\n"
168 "Note: roll=rotate about x, pitch=rotate about y, yaw=rotate about z"
169 );
171 argList::addArgument("input", "The input surface file");
172 argList::addArgument("output", "The output surface file");
174 (
175 "recentre",
176 "Recentre the bounding box before other operations"
177 );
179 (
180 "translate",
181 "vector",
182 "Translate by specified <vector> before rotations"
183 );
185 (
186 "auto-centre",
187 "Use bounding box centre as centre for rotations"
188 );
190 (
191 "centre",
192 "point",
193 "Use specified <point> as centre for rotations"
194 );
195 argList::addOptionCompat("auto-centre", {"auto-origin", 2206});
196 argList::addOptionCompat("centre", {"origin", 2206});
197
199 (
200 "rotate",
201 "(vectorA vectorB)",
202 "Rotate from <vectorA> to <vectorB> - eg, '((1 0 0) (0 0 1))'"
203 );
205 (
206 "rotate-angle",
207 "(vector angle)",
208 "Rotate <angle> degrees about <vector> - eg, '((1 0 0) 45)'"
209 );
211 (
212 "rotate-x", "deg",
213 "Rotate (degrees) about x-axis"
214 );
216 (
217 "rotate-y", "deg",
218 "Rotate (degrees) about y-axis"
219 );
221 (
222 "rotate-z", "deg",
223 "Rotate (degrees) about z-axis"
224 );
226 (
227 "rollPitchYaw",
228 "vector",
229 "Rotate by '(roll pitch yaw)' degrees"
230 );
232 (
233 "yawPitchRoll",
234 "vector",
235 "Rotate by '(yaw pitch roll)' degrees"
236 );
238 (
239 "read-scale",
240 "scalar | vector",
241 "Uniform or non-uniform input scaling"
242 );
244 (
245 "write-scale",
246 "scalar | vector",
247 "Uniform or non-uniform output scaling"
248 );
250 (
251 "read-format",
252 "type",
253 "Input format (default: use file extension)"
254 );
256 (
257 "write-format",
258 "type",
259 "Output format (default: use file extension)"
260 );
262 (
263 "cylToCart",
264 "(originVec axisVec directionVec)",
265 "Tranform cylindrical coordinates to cartesian coordinates"
266 );
267
268 // Backward compatibility and with transformPoints
269 argList::addOptionCompat("write-scale", {"scale", -2006});
270
271 argList args(argc, argv);
272
273 // Verify that an operation has been specified
274 {
275 const List<word> operationNames
276 ({
277 "recentre",
278 "translate",
279 "rotate",
280 "rotate-angle",
281 "rotate-x",
282 "rotate-y",
283 "rotate-z",
284 "rollPitchYaw",
285 "yawPitchRoll",
286 "read-scale",
287 "write-scale",
288 "cylToCart"
289 });
290
291 if (!args.count(operationNames))
292 {
294 << "No operation supplied, "
295 << "use at least one of the following:" << nl
296 << " ";
297
298 for (const auto& opName : operationNames)
299 {
301 << " -" << opName;
302 }
303
305 << nl << exit(FatalError);
306 }
307 }
308
309 const auto importName = args.get<fileName>(1);
310 const auto exportName = args.get<fileName>(2);
311
312 const word readFileType
313 (
314 args.getOrDefault<word>("read-format", getExtension(importName))
315 );
316
317 const word writeFileType
318 (
319 args.getOrDefault<word>("write-format", getExtension(exportName))
320 );
321
322
323 // Check that reading/writing is supported
324 if (!hasReadWriteTypes(readFileType, writeFileType))
325 {
327 << "Unsupported file format(s)" << nl
328 << exit(FatalError);
329 }
330
331
332 Info<< "Reading surf from " << importName << " ..." << nl
333 << "Writing surf to " << exportName << " ..." << endl;
334
335
336 meshedSurface surf1(importName, readFileType);
337
338 pointField points(surf1.points());
339
340
341 // Begin operations
342
343 // Input scaling
344 applyScaling(points, getScalingOpt("read-scale", args));
345
346 vector v;
347 if (args.found("recentre"))
348 {
349 v = boundBox(points).centre();
350 Info<< "Adjust centre " << v << " -> (0 0 0)" << endl;
351 points -= v;
352 }
353
354 if (args.readIfPresent("translate", v))
355 {
356 Info<< "Translating points by " << v << endl;
357 points += v;
358 }
359
360 vector rotationCentre;
361 bool useRotationCentre = args.readIfPresent("centre", rotationCentre);
362 if (args.found("auto-centre") && !useRotationCentre)
363 {
364 useRotationCentre = true;
365 rotationCentre = boundBox(points).centre();
366 }
367
368 if (useRotationCentre)
369 {
370 Info<< "Set centre of rotation to " << rotationCentre << endl;
371 points -= rotationCentre;
372 }
373
374
375 // Get a rotation specification
376
377 tensor rot(Zero);
378 bool useRotation(false);
379
380 if (args.found("rotate"))
381 {
382 Pair<vector> n1n2
383 (
384 args.lookup("rotate")()
385 );
386 n1n2[0].normalise();
387 n1n2[1].normalise();
388
389 rot = rotationTensor(n1n2[0], n1n2[1]);
390 useRotation = true;
391 }
392 else if (args.found("rotate-angle"))
393 {
394 const Tuple2<vector, scalar> rotAxisAngle
395 (
396 args.lookup("rotate-angle")()
397 );
398
399 const vector& axis = rotAxisAngle.first();
400 const scalar angle = rotAxisAngle.second();
401
402 Info<< "Rotating points " << nl
403 << " about " << axis << nl
404 << " angle " << angle << nl;
405
406 rot = axisAngle::rotation(axis, angle, true);
407 useRotation = true;
408 }
409 else if (args.found("rotate-x"))
410 {
411 const scalar angle = args.get<scalar>("rotate-x");
412
413 Info<< "Rotating points about x-axis: " << angle << nl;
414
415 rot = axisAngle::rotation(vector::X, angle, true);
416 useRotation = true;
417 }
418 else if (args.found("rotate-y"))
419 {
420 const scalar angle = args.get<scalar>("rotate-y");
421
422 Info<< "Rotating points about y-axis: " << angle << nl;
423
424 rot = axisAngle::rotation(vector::Y, angle, true);
425 useRotation = true;
426 }
427 else if (args.found("rotate-z"))
428 {
429 const scalar angle = args.get<scalar>("rotate-z");
430
431 Info<< "Rotating points about z-axis: " << angle << nl;
432
433 rot = axisAngle::rotation(vector::Z, angle, true);
434 useRotation = true;
435 }
436 else if (args.readIfPresent("rollPitchYaw", v))
437 {
438 Info<< "Rotating points by" << nl
439 << " roll " << v.x() << nl
440 << " pitch " << v.y() << nl
441 << " yaw " << v.z() << nl;
442
443 rot = euler::rotation(euler::eulerOrder::ROLL_PITCH_YAW, v, true);
444 useRotation = true;
445 }
446 else if (args.readIfPresent("yawPitchRoll", v))
447 {
448 Info<< "Rotating points by" << nl
449 << " yaw " << v.x() << nl
450 << " pitch " << v.y() << nl
451 << " roll " << v.z() << nl;
452
453 rot = euler::rotation(euler::eulerOrder::YAW_PITCH_ROLL, v, true);
454 useRotation = true;
455 }
456
457 if (useRotation)
458 {
459 Info<< "Rotating points by " << rot << endl;
460 transform(points, rot, points);
461 }
462
463 if (useRotationCentre)
464 {
465 Info<< "Unset centre of rotation from " << rotationCentre << endl;
466 points += rotationCentre;
467 }
468
469 // Output scaling
470 applyScaling(points, getScalingOpt("write-scale", args));
471
472 // Conversion to cylindrical coords
473 if (args.found("cylToCart"))
474 {
475 vectorField n1n2(args.lookup("cylToCart")());
476 n1n2[1].normalise();
477 n1n2[2].normalise();
478
479 cylindricalCS ccs
480 (
481 "ccs",
482 n1n2[0],
483 n1n2[1],
484 n1n2[2]
485 );
486
487 points = ccs.globalPosition(points);
488 }
489
490 surf1.movePoints(points);
491 surf1.write(exportName, writeFileType);
492
493 Info<< "End\n" << endl;
494
495 return 0;
496}
497
498
499// ************************************************************************* //
void resize(const label len)
Adjust allocated size of list.
Definition ListI.H:153
void clear()
Clear the list, i.e. set size to zero.
Definition ListI.H:133
static bool canWriteType(const word &fileType, bool verbose=false)
static bool canReadType(const word &fileType, bool verbose=false)
A 2-tuple for storing two objects of dissimilar types. The container is similar in purpose to std::pa...
Definition Tuple2.H:51
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 addBoolOption(const word &optName, const string &usage="", bool advanced=false)
Add a bool option to validOptions with usage information.
Definition argList.C:389
static void noParallel()
Remove the parallel options.
Definition argList.C:599
static void addOption(const word &optName, const string &param="", const string &usage="", bool advanced=false)
Add an option to validOptions with usage information.
Definition argList.C:400
static void addNote(const string &note)
Add extra notes for the usage information.
Definition argList.C:477
static void addOptionCompat(const word &optName, std::pair< const char *, int > compat)
Specify an alias for the option name.
Definition argList.C:433
A bounding box defined in terms of min/max extrema points.
Definition boundBox.H:71
point centre() const
The centre (midpoint) of the bounding box.
Definition boundBoxI.H:186
static tensor rotation(const vector &axis, const scalar angle, bool degrees=false)
The rotation tensor for given axis/angle.
static tensor rotation(const vector &angles, bool degrees=false)
Rotation tensor calculated for the intrinsic Euler angles in z-x-z order.
A class for handling file names.
Definition fileName.H:75
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:66
auto & name
const pointField & points
Namespace for coordinate system rotations.
Namespace for OpenFOAM.
tensor rotationTensor(const vector &n1, const vector &n2)
Rotational transformation tensor from vector n1 to n2.
Definition transform.H:47
bool equal(const T &a, const T &b)
Compare two values for equality.
Definition label.H:180
refinementData transform(const tensor &, const refinementData val)
No-op rotational transform for base types.
messageStream Info
Information stream (stdout output on master, null elsewhere).
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition Ostream.H:519
MeshedSurface< face > meshedSurface
coordSystem::cylindrical cylindricalCS
Compatibility typedef 1806.
Field< vector > vectorField
Specialisation of Field<T> for vector.
static constexpr const zero Zero
Global zero (0).
Definition zero.H:127
dimensioned< Type > cmptMultiply(const dimensioned< Type > &, const dimensioned< Type > &)
error FatalError
Error stream (stdout output on all processes), with additional 'FOAM FATAL ERROR' header text and sta...
vectorField pointField
pointField is a vectorField.
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
Foam::argList args(argc, argv)
Spatial transformation functions for primitive fields.